Web Inspector: Remove leftover 'device metrics' code
[WebKit-https.git] / Source / WebCore / page / DOMWindow.cpp
1 /*
2  * Copyright (C) 2006, 2007, 2008, 2010, 2013 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 "BackForwardController.h"
31 #include "BarProp.h"
32 #include "BeforeUnloadEvent.h"
33 #include "CSSComputedStyleDeclaration.h"
34 #include "CSSRule.h"
35 #include "CSSRuleList.h"
36 #include "Chrome.h"
37 #include "ChromeClient.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 "DOMWindowCSS.h"
48 #include "DOMWindowExtension.h"
49 #include "DOMWindowNotifications.h"
50 #include "DeviceMotionController.h"
51 #include "DeviceOrientationController.h"
52 #include "Document.h"
53 #include "DocumentLoader.h"
54 #include "Editor.h"
55 #include "Element.h"
56 #include "EventException.h"
57 #include "EventHandler.h"
58 #include "EventListener.h"
59 #include "EventNames.h"
60 #include "ExceptionCode.h"
61 #include "ExceptionCodePlaceholder.h"
62 #include "FloatRect.h"
63 #include "FocusController.h"
64 #include "FrameLoadRequest.h"
65 #include "FrameLoader.h"
66 #include "FrameLoaderClient.h"
67 #include "FrameTree.h"
68 #include "FrameView.h"
69 #include "HTMLFrameOwnerElement.h"
70 #include "History.h"
71 #include "InspectorInstrumentation.h"
72 #include "URL.h"
73 #include "Location.h"
74 #include "MainFrame.h"
75 #include "MediaQueryList.h"
76 #include "MediaQueryMatcher.h"
77 #include "MessageEvent.h"
78 #include "Navigator.h"
79 #include "Page.h"
80 #include "PageConsole.h"
81 #include "PageGroup.h"
82 #include "PageTransitionEvent.h"
83 #include "Performance.h"
84 #include "PlatformScreen.h"
85 #include "RuntimeEnabledFeatures.h"
86 #include "ScheduledAction.h"
87 #include "Screen.h"
88 #include "ScriptCallStack.h"
89 #include "ScriptCallStackFactory.h"
90 #include "ScriptController.h"
91 #include "SecurityOrigin.h"
92 #include "SecurityPolicy.h"
93 #include "SerializedScriptValue.h"
94 #include "Settings.h"
95 #include "Storage.h"
96 #include "StorageArea.h"
97 #include "StorageNamespace.h"
98 #include "StyleMedia.h"
99 #include "StyleResolver.h"
100 #include "SuddenTermination.h"
101 #include "WebKitPoint.h"
102 #include "WindowFeatures.h"
103 #include "WindowFocusAllowedIndicator.h"
104 #include <algorithm>
105 #include <wtf/CurrentTime.h>
106 #include <wtf/MainThread.h>
107 #include <wtf/MathExtras.h>
108 #include <wtf/Ref.h>
109 #include <wtf/text/Base64.h>
110 #include <wtf/text/WTFString.h>
111
112 #if ENABLE(PROXIMITY_EVENTS)
113 #include "DeviceProximityController.h"
114 #endif
115
116 #if ENABLE(REQUEST_ANIMATION_FRAME)
117 #include "RequestAnimationFrameCallback.h"
118 #endif
119
120 #if PLATFORM(IOS)
121 #if ENABLE(GEOLOCATION)
122 #include "NavigatorGeolocation.h"
123 #endif
124 #include "WKContentObservation.h"
125 #endif
126
127 namespace WebCore {
128
129 class PostMessageTimer : public TimerBase {
130 public:
131     PostMessageTimer(DOMWindow* window, PassRefPtr<SerializedScriptValue> message, const String& sourceOrigin, PassRefPtr<DOMWindow> source, PassOwnPtr<MessagePortChannelArray> channels, SecurityOrigin* targetOrigin, PassRefPtr<ScriptCallStack> stackTrace)
132         : m_window(window)
133         , m_message(message)
134         , m_origin(sourceOrigin)
135         , m_source(source)
136         , m_channels(channels)
137         , m_targetOrigin(targetOrigin)
138         , m_stackTrace(stackTrace)
139     {
140     }
141
142     PassRefPtr<MessageEvent> event(ScriptExecutionContext* context)
143     {
144         OwnPtr<MessagePortArray> messagePorts = MessagePort::entanglePorts(*context, m_channels.release());
145         return MessageEvent::create(messagePorts.release(), m_message, m_origin, String(), m_source);
146     }
147     SecurityOrigin* targetOrigin() const { return m_targetOrigin.get(); }
148     ScriptCallStack* stackTrace() const { return m_stackTrace.get(); }
149
150 private:
151     virtual void fired()
152     {
153         m_window->postMessageTimerFired(adoptPtr(this));
154         // This object is deleted now.
155     }
156
157     RefPtr<DOMWindow> m_window;
158     RefPtr<SerializedScriptValue> m_message;
159     String m_origin;
160     RefPtr<DOMWindow> m_source;
161     OwnPtr<MessagePortChannelArray> m_channels;
162     RefPtr<SecurityOrigin> m_targetOrigin;
163     RefPtr<ScriptCallStack> m_stackTrace;
164 };
165
166 typedef HashCountedSet<DOMWindow*> DOMWindowSet;
167
168 static DOMWindowSet& windowsWithUnloadEventListeners()
169 {
170     DEFINE_STATIC_LOCAL(DOMWindowSet, windowsWithUnloadEventListeners, ());
171     return windowsWithUnloadEventListeners;
172 }
173
174 static DOMWindowSet& windowsWithBeforeUnloadEventListeners()
175 {
176     DEFINE_STATIC_LOCAL(DOMWindowSet, windowsWithBeforeUnloadEventListeners, ());
177     return windowsWithBeforeUnloadEventListeners;
178 }
179
180 static void addUnloadEventListener(DOMWindow* domWindow)
181 {
182     if (windowsWithUnloadEventListeners().add(domWindow).isNewEntry)
183         domWindow->disableSuddenTermination();
184 }
185
186 static void removeUnloadEventListener(DOMWindow* domWindow)
187 {
188     if (windowsWithUnloadEventListeners().remove(domWindow))
189         domWindow->enableSuddenTermination();
190 }
191
192 static void removeAllUnloadEventListeners(DOMWindow* domWindow)
193 {
194     if (windowsWithUnloadEventListeners().removeAll(domWindow))
195         domWindow->enableSuddenTermination();
196 }
197
198 static void addBeforeUnloadEventListener(DOMWindow* domWindow)
199 {
200     if (windowsWithBeforeUnloadEventListeners().add(domWindow).isNewEntry)
201         domWindow->disableSuddenTermination();
202 }
203
204 static void removeBeforeUnloadEventListener(DOMWindow* domWindow)
205 {
206     if (windowsWithBeforeUnloadEventListeners().remove(domWindow))
207         domWindow->enableSuddenTermination();
208 }
209
210 static void removeAllBeforeUnloadEventListeners(DOMWindow* domWindow)
211 {
212     if (windowsWithBeforeUnloadEventListeners().removeAll(domWindow))
213         domWindow->enableSuddenTermination();
214 }
215
216 static bool allowsBeforeUnloadListeners(DOMWindow* window)
217 {
218     ASSERT_ARG(window, window);
219     Frame* frame = window->frame();
220     if (!frame)
221         return false;
222     if (!frame->page())
223         return false;
224     return frame->isMainFrame();
225 }
226
227 bool DOMWindow::dispatchAllPendingBeforeUnloadEvents()
228 {
229     DOMWindowSet& set = windowsWithBeforeUnloadEventListeners();
230     if (set.isEmpty())
231         return true;
232
233     static bool alreadyDispatched = false;
234     ASSERT(!alreadyDispatched);
235     if (alreadyDispatched)
236         return true;
237
238     Vector<Ref<DOMWindow>> windows;
239     windows.reserveInitialCapacity(set.size());
240     for (auto it = set.begin(), end = set.end(); it != end; ++it)
241         windows.uncheckedAppend(*it->key);
242
243     for (unsigned i = 0; i < windows.size(); ++i) {
244         DOMWindow& window = windows[i].get();
245         if (!set.contains(&window))
246             continue;
247
248         Frame* frame = window.frame();
249         if (!frame)
250             continue;
251
252         if (!frame->loader().shouldClose())
253             return false;
254
255         window.enableSuddenTermination();
256     }
257
258     alreadyDispatched = true;
259     return true;
260 }
261
262 unsigned DOMWindow::pendingUnloadEventListeners() const
263 {
264     return windowsWithUnloadEventListeners().count(const_cast<DOMWindow*>(this));
265 }
266
267 void DOMWindow::dispatchAllPendingUnloadEvents()
268 {
269     DOMWindowSet& set = windowsWithUnloadEventListeners();
270     if (set.isEmpty())
271         return;
272
273     static bool alreadyDispatched = false;
274     ASSERT(!alreadyDispatched);
275     if (alreadyDispatched)
276         return;
277
278     Vector<Ref<DOMWindow>> windows;
279     windows.reserveInitialCapacity(set.size());
280     for (auto it = set.begin(), end = set.end(); it != end; ++it)
281         windows.uncheckedAppend(*it->key);
282
283     for (unsigned i = 0; i < windows.size(); ++i) {
284         DOMWindow& window = windows[i].get();
285         if (!set.contains(&window))
286             continue;
287
288         window.dispatchEvent(PageTransitionEvent::create(eventNames().pagehideEvent, false), window.document());
289         window.dispatchEvent(Event::create(eventNames().unloadEvent, false, false), window.document());
290
291         window.enableSuddenTermination();
292     }
293
294     alreadyDispatched = true;
295 }
296
297 // This function:
298 // 1) Validates the pending changes are not changing any value to NaN; in that case keep original value.
299 // 2) Constrains the window rect to the minimum window size and no bigger than the float rect's dimensions.
300 // 3) Constrains the window rect to within the top and left boundaries of the available screen rect.
301 // 4) Constrains the window rect to within the bottom and right boundaries of the available screen rect.
302 // 5) Translate the window rect coordinates to be within the coordinate space of the screen.
303 FloatRect DOMWindow::adjustWindowRect(Page* page, const FloatRect& pendingChanges)
304 {
305     ASSERT(page);
306
307     FloatRect screen = screenAvailableRect(page->mainFrame().view());
308     FloatRect window = page->chrome().windowRect();
309
310     // Make sure we're in a valid state before adjusting dimensions.
311     ASSERT(std::isfinite(screen.x()));
312     ASSERT(std::isfinite(screen.y()));
313     ASSERT(std::isfinite(screen.width()));
314     ASSERT(std::isfinite(screen.height()));
315     ASSERT(std::isfinite(window.x()));
316     ASSERT(std::isfinite(window.y()));
317     ASSERT(std::isfinite(window.width()));
318     ASSERT(std::isfinite(window.height()));
319
320     // Update window values if new requested values are not NaN.
321     if (!std::isnan(pendingChanges.x()))
322         window.setX(pendingChanges.x());
323     if (!std::isnan(pendingChanges.y()))
324         window.setY(pendingChanges.y());
325     if (!std::isnan(pendingChanges.width()))
326         window.setWidth(pendingChanges.width());
327     if (!std::isnan(pendingChanges.height()))
328         window.setHeight(pendingChanges.height());
329
330     FloatSize minimumSize = page->chrome().client().minimumWindowSize();
331     window.setWidth(std::min(std::max(minimumSize.width(), window.width()), screen.width()));
332     window.setHeight(std::min(std::max(minimumSize.height(), window.height()), screen.height()));
333
334     // Constrain the window position within the valid screen area.
335     window.setX(std::max(screen.x(), std::min(window.x(), screen.maxX() - window.width())));
336     window.setY(std::max(screen.y(), std::min(window.y(), screen.maxY() - window.height())));
337
338     return window;
339 }
340
341 bool DOMWindow::allowPopUp(Frame* firstFrame)
342 {
343     ASSERT(firstFrame);
344
345     if (ScriptController::processingUserGesture())
346         return true;
347
348     return firstFrame->settings().javaScriptCanOpenWindowsAutomatically();
349 }
350
351 bool DOMWindow::allowPopUp()
352 {
353     return m_frame && allowPopUp(m_frame);
354 }
355
356 bool DOMWindow::canShowModalDialog(const Frame* frame)
357 {
358     if (!frame)
359         return false;
360     Page* page = frame->page();
361     if (!page)
362         return false;
363     return page->chrome().canRunModal();
364 }
365
366 bool DOMWindow::canShowModalDialogNow(const Frame* frame)
367 {
368     if (!frame)
369         return false;
370     Page* page = frame->page();
371     if (!page)
372         return false;
373     return page->chrome().canRunModalNow();
374 }
375
376 DOMWindow::DOMWindow(Document* document)
377     : ContextDestructionObserver(document)
378     , FrameDestructionObserver(document->frame())
379     , m_shouldPrintWhenFinishedLoading(false)
380     , m_suspendedForPageCache(false)
381     , m_lastPageStatus(PageStatusNone)
382 #if PLATFORM(IOS)
383     , m_scrollEventListenerCount(0)
384 #endif
385 #if ENABLE(IOS_TOUCH_EVENTS) || ENABLE(IOS_GESTURE_EVENTS)
386     , m_touchEventListenerCount(0)
387 #endif
388 {
389     ASSERT(frame());
390     ASSERT(DOMWindow::document());
391 }
392
393 void DOMWindow::didSecureTransitionTo(Document* document)
394 {
395     observeContext(document);
396 }
397
398 DOMWindow::~DOMWindow()
399 {
400 #ifndef NDEBUG
401     if (!m_suspendedForPageCache) {
402         ASSERT(!m_screen);
403         ASSERT(!m_history);
404         ASSERT(!m_crypto);
405         ASSERT(!m_locationbar);
406         ASSERT(!m_menubar);
407         ASSERT(!m_personalbar);
408         ASSERT(!m_scrollbars);
409         ASSERT(!m_statusbar);
410         ASSERT(!m_toolbar);
411         ASSERT(!m_console);
412         ASSERT(!m_navigator);
413 #if ENABLE(WEB_TIMING)
414         ASSERT(!m_performance);
415 #endif
416         ASSERT(!m_location);
417         ASSERT(!m_media);
418         ASSERT(!m_sessionStorage);
419         ASSERT(!m_localStorage);
420         ASSERT(!m_applicationCache);
421     }
422 #endif
423
424     if (m_suspendedForPageCache)
425         willDestroyCachedFrame();
426     else
427         willDestroyDocumentInFrame();
428
429     // As the ASSERTs above indicate, this reset should only be necessary if this DOMWindow is suspended for the page cache.
430     // But we don't want to risk any of these objects hanging around after we've been destroyed.
431     resetDOMWindowProperties();
432
433     removeAllUnloadEventListeners(this);
434     removeAllBeforeUnloadEventListeners(this);
435 }
436
437 DOMWindow* DOMWindow::toDOMWindow()
438 {
439     return this;
440 }
441
442 PassRefPtr<MediaQueryList> DOMWindow::matchMedia(const String& media)
443 {
444     return document() ? document()->mediaQueryMatcher().matchMedia(media) : 0;
445 }
446
447 Page* DOMWindow::page()
448 {
449     return frame() ? frame()->page() : 0;
450 }
451
452 void DOMWindow::frameDestroyed()
453 {
454     willDestroyDocumentInFrame();
455     FrameDestructionObserver::frameDestroyed();
456     resetDOMWindowProperties();
457 }
458
459 void DOMWindow::willDetachPage()
460 {
461     InspectorInstrumentation::frameWindowDiscarded(m_frame, this);
462 }
463
464 void DOMWindow::willDestroyCachedFrame()
465 {
466     // It is necessary to copy m_properties to a separate vector because the DOMWindowProperties may
467     // unregister themselves from the DOMWindow as a result of the call to willDestroyGlobalObjectInCachedFrame.
468     Vector<DOMWindowProperty*> properties;
469     copyToVector(m_properties, properties);
470     for (size_t i = 0; i < properties.size(); ++i)
471         properties[i]->willDestroyGlobalObjectInCachedFrame();
472 }
473
474 void DOMWindow::willDestroyDocumentInFrame()
475 {
476     // It is necessary to copy m_properties to a separate vector because the DOMWindowProperties may
477     // unregister themselves from the DOMWindow as a result of the call to willDestroyGlobalObjectInFrame.
478     Vector<DOMWindowProperty*> properties;
479     copyToVector(m_properties, properties);
480     for (size_t i = 0; i < properties.size(); ++i)
481         properties[i]->willDestroyGlobalObjectInFrame();
482 }
483
484 void DOMWindow::willDetachDocumentFromFrame()
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 willDetachGlobalObjectFromFrame.
488     Vector<DOMWindowProperty*> properties;
489     copyToVector(m_properties, properties);
490     for (size_t i = 0; i < properties.size(); ++i)
491         properties[i]->willDetachGlobalObjectFromFrame();
492 }
493
494 void DOMWindow::registerProperty(DOMWindowProperty* property)
495 {
496     m_properties.add(property);
497 }
498
499 void DOMWindow::unregisterProperty(DOMWindowProperty* property)
500 {
501     m_properties.remove(property);
502 }
503
504 void DOMWindow::resetUnlessSuspendedForPageCache()
505 {
506     if (m_suspendedForPageCache)
507         return;
508     willDestroyDocumentInFrame();
509     resetDOMWindowProperties();
510 }
511
512 void DOMWindow::suspendForPageCache()
513 {
514     disconnectDOMWindowProperties();
515     m_suspendedForPageCache = true;
516 }
517
518 void DOMWindow::resumeFromPageCache()
519 {
520     reconnectDOMWindowProperties();
521     m_suspendedForPageCache = false;
522 }
523
524 void DOMWindow::disconnectDOMWindowProperties()
525 {
526     // It is necessary to copy m_properties to a separate vector because the DOMWindowProperties may
527     // unregister themselves from the DOMWindow as a result of the call to disconnectFrameForPageCache.
528     Vector<DOMWindowProperty*> properties;
529     copyToVector(m_properties, properties);
530     for (size_t i = 0; i < properties.size(); ++i)
531         properties[i]->disconnectFrameForPageCache();
532 }
533
534 void DOMWindow::reconnectDOMWindowProperties()
535 {
536     ASSERT(m_suspendedForPageCache);
537     // It is necessary to copy m_properties to a separate vector because the DOMWindowProperties may
538     // unregister themselves from the DOMWindow as a result of the call to reconnectFromPageCache.
539     Vector<DOMWindowProperty*> properties;
540     copyToVector(m_properties, properties);
541     for (size_t i = 0; i < properties.size(); ++i)
542         properties[i]->reconnectFrameFromPageCache(m_frame);
543 }
544
545 void DOMWindow::resetDOMWindowProperties()
546 {
547     m_properties.clear();
548
549     m_screen = 0;
550     m_history = 0;
551     m_crypto = 0;
552     m_locationbar = 0;
553     m_menubar = 0;
554     m_personalbar = 0;
555     m_scrollbars = 0;
556     m_statusbar = 0;
557     m_toolbar = 0;
558     m_console = 0;
559     m_navigator = 0;
560 #if ENABLE(WEB_TIMING)
561     m_performance = 0;
562 #endif
563     m_location = 0;
564     m_media = 0;
565     m_sessionStorage = 0;
566     m_localStorage = 0;
567     m_applicationCache = 0;
568 }
569
570 bool DOMWindow::isCurrentlyDisplayedInFrame() const
571 {
572     return m_frame && m_frame->document()->domWindow() == this;
573 }
574
575 #if ENABLE(ORIENTATION_EVENTS)
576 int DOMWindow::orientation() const
577 {
578     if (!m_frame)
579         return 0;
580
581     return m_frame->orientation();
582 }
583 #endif
584
585 Screen* DOMWindow::screen() const
586 {
587     if (!isCurrentlyDisplayedInFrame())
588         return 0;
589     if (!m_screen)
590         m_screen = Screen::create(m_frame);
591     return m_screen.get();
592 }
593
594 History* DOMWindow::history() const
595 {
596     if (!isCurrentlyDisplayedInFrame())
597         return 0;
598     if (!m_history)
599         m_history = History::create(m_frame);
600     return m_history.get();
601 }
602
603 Crypto* DOMWindow::crypto() const
604 {
605     // FIXME: Why is crypto not available when the window is not currently displayed in a frame?
606     if (!isCurrentlyDisplayedInFrame())
607         return 0;
608     if (!m_crypto)
609         m_crypto = Crypto::create(*document());
610     return m_crypto.get();
611 }
612
613 BarProp* DOMWindow::locationbar() const
614 {
615     if (!isCurrentlyDisplayedInFrame())
616         return 0;
617     if (!m_locationbar)
618         m_locationbar = BarProp::create(m_frame, BarProp::Locationbar);
619     return m_locationbar.get();
620 }
621
622 BarProp* DOMWindow::menubar() const
623 {
624     if (!isCurrentlyDisplayedInFrame())
625         return 0;
626     if (!m_menubar)
627         m_menubar = BarProp::create(m_frame, BarProp::Menubar);
628     return m_menubar.get();
629 }
630
631 BarProp* DOMWindow::personalbar() const
632 {
633     if (!isCurrentlyDisplayedInFrame())
634         return 0;
635     if (!m_personalbar)
636         m_personalbar = BarProp::create(m_frame, BarProp::Personalbar);
637     return m_personalbar.get();
638 }
639
640 BarProp* DOMWindow::scrollbars() const
641 {
642     if (!isCurrentlyDisplayedInFrame())
643         return 0;
644     if (!m_scrollbars)
645         m_scrollbars = BarProp::create(m_frame, BarProp::Scrollbars);
646     return m_scrollbars.get();
647 }
648
649 BarProp* DOMWindow::statusbar() const
650 {
651     if (!isCurrentlyDisplayedInFrame())
652         return 0;
653     if (!m_statusbar)
654         m_statusbar = BarProp::create(m_frame, BarProp::Statusbar);
655     return m_statusbar.get();
656 }
657
658 BarProp* DOMWindow::toolbar() const
659 {
660     if (!isCurrentlyDisplayedInFrame())
661         return 0;
662     if (!m_toolbar)
663         m_toolbar = BarProp::create(m_frame, BarProp::Toolbar);
664     return m_toolbar.get();
665 }
666
667 Console* DOMWindow::console() const
668 {
669     if (!isCurrentlyDisplayedInFrame())
670         return 0;
671     if (!m_console)
672         m_console = Console::create(m_frame);
673     return m_console.get();
674 }
675
676 PageConsole* DOMWindow::pageConsole() const
677 {
678     if (!isCurrentlyDisplayedInFrame())
679         return 0;
680     return m_frame->page() ? &m_frame->page()->console() : 0;
681 }
682
683 DOMApplicationCache* DOMWindow::applicationCache() const
684 {
685     if (!isCurrentlyDisplayedInFrame())
686         return 0;
687     if (!m_applicationCache)
688         m_applicationCache = DOMApplicationCache::create(m_frame);
689     return m_applicationCache.get();
690 }
691
692 Navigator* DOMWindow::navigator() const
693 {
694     if (!isCurrentlyDisplayedInFrame())
695         return 0;
696     if (!m_navigator)
697         m_navigator = Navigator::create(m_frame);
698     return m_navigator.get();
699 }
700
701 #if ENABLE(WEB_TIMING)
702 Performance* DOMWindow::performance() const
703 {
704     if (!isCurrentlyDisplayedInFrame())
705         return 0;
706     if (!m_performance)
707         m_performance = Performance::create(m_frame);
708     return m_performance.get();
709 }
710 #endif
711
712 Location* DOMWindow::location() const
713 {
714     if (!isCurrentlyDisplayedInFrame())
715         return 0;
716     if (!m_location)
717         m_location = Location::create(m_frame);
718     return m_location.get();
719 }
720
721 Storage* DOMWindow::sessionStorage(ExceptionCode& ec) const
722 {
723     if (!isCurrentlyDisplayedInFrame())
724         return 0;
725
726     Document* document = this->document();
727     if (!document)
728         return 0;
729
730     if (!document->securityOrigin()->canAccessSessionStorage(document->topOrigin())) {
731         ec = SECURITY_ERR;
732         return 0;
733     }
734
735     if (m_sessionStorage) {
736         if (!m_sessionStorage->area().canAccessStorage(m_frame)) {
737             ec = SECURITY_ERR;
738             return 0;
739         }
740         return m_sessionStorage.get();
741     }
742
743     Page* page = document->page();
744     if (!page)
745         return 0;
746
747     RefPtr<StorageArea> storageArea = page->sessionStorage()->storageArea(document->securityOrigin());
748     if (!storageArea->canAccessStorage(m_frame)) {
749         ec = SECURITY_ERR;
750         return 0;
751     }
752
753     m_sessionStorage = Storage::create(m_frame, storageArea.release());
754     return m_sessionStorage.get();
755 }
756
757 Storage* DOMWindow::localStorage(ExceptionCode& ec) const
758 {
759     if (!isCurrentlyDisplayedInFrame())
760         return 0;
761
762     Document* document = this->document();
763     if (!document)
764         return 0;
765
766     if (!document->securityOrigin()->canAccessLocalStorage(0)) {
767         ec = SECURITY_ERR;
768         return 0;
769     }
770
771     if (m_localStorage) {
772         if (!m_localStorage->area().canAccessStorage(m_frame)) {
773             ec = SECURITY_ERR;
774             return 0;
775         }
776         return m_localStorage.get();
777     }
778
779     Page* page = document->page();
780     if (!page)
781         return 0;
782
783     if (!page->settings().localStorageEnabled())
784         return 0;
785
786     RefPtr<StorageArea> storageArea;
787     if (!document->securityOrigin()->canAccessLocalStorage(document->topOrigin()))
788         storageArea = page->group().transientLocalStorage(document->topOrigin())->storageArea(document->securityOrigin());
789     else
790         storageArea = page->group().localStorage()->storageArea(document->securityOrigin());
791
792     if (!storageArea->canAccessStorage(m_frame)) {
793         ec = SECURITY_ERR;
794         return 0;
795     }
796
797     m_localStorage = Storage::create(m_frame, storageArea.release());
798     return m_localStorage.get();
799 }
800
801 void DOMWindow::postMessage(PassRefPtr<SerializedScriptValue> message, MessagePort* port, const String& targetOrigin, DOMWindow& source, ExceptionCode& ec)
802 {
803     MessagePortArray ports;
804     if (port)
805         ports.append(port);
806     postMessage(message, &ports, targetOrigin, source, ec);
807 }
808
809 void DOMWindow::postMessage(PassRefPtr<SerializedScriptValue> message, const MessagePortArray* ports, const String& targetOrigin, DOMWindow& source, ExceptionCode& ec)
810 {
811     if (!isCurrentlyDisplayedInFrame())
812         return;
813
814     Document* sourceDocument = source.document();
815
816     // Compute the target origin.  We need to do this synchronously in order
817     // to generate the SYNTAX_ERR exception correctly.
818     RefPtr<SecurityOrigin> target;
819     if (targetOrigin == "/") {
820         if (!sourceDocument)
821             return;
822         target = sourceDocument->securityOrigin();
823     } else if (targetOrigin != "*") {
824         target = SecurityOrigin::createFromString(targetOrigin);
825         // It doesn't make sense target a postMessage at a unique origin
826         // because there's no way to represent a unique origin in a string.
827         if (target->isUnique()) {
828             ec = SYNTAX_ERR;
829             return;
830         }
831     }
832
833     OwnPtr<MessagePortChannelArray> channels = MessagePort::disentanglePorts(ports, ec);
834     if (ec)
835         return;
836
837     // Capture the source of the message.  We need to do this synchronously
838     // in order to capture the source of the message correctly.
839     if (!sourceDocument)
840         return;
841     String sourceOrigin = sourceDocument->securityOrigin()->toString();
842
843     // Capture stack trace only when inspector front-end is loaded as it may be time consuming.
844     RefPtr<ScriptCallStack> stackTrace;
845     if (InspectorInstrumentation::consoleAgentEnabled(sourceDocument))
846         stackTrace = createScriptCallStack(ScriptCallStack::maxCallStackSizeToCapture, true);
847
848     // Schedule the message.
849     PostMessageTimer* timer = new PostMessageTimer(this, message, sourceOrigin, &source, channels.release(), target.get(), stackTrace.release());
850     timer->startOneShot(0);
851 }
852
853 void DOMWindow::postMessageTimerFired(PassOwnPtr<PostMessageTimer> t)
854 {
855     OwnPtr<PostMessageTimer> timer(t);
856
857     if (!document() || !isCurrentlyDisplayedInFrame())
858         return;
859
860     dispatchMessageEventWithOriginCheck(timer->targetOrigin(), timer->event(document()), timer->stackTrace());
861 }
862
863 void DOMWindow::dispatchMessageEventWithOriginCheck(SecurityOrigin* intendedTargetOrigin, PassRefPtr<Event> event, PassRefPtr<ScriptCallStack> stackTrace)
864 {
865     if (intendedTargetOrigin) {
866         // Check target origin now since the target document may have changed since the timer was scheduled.
867         if (!intendedTargetOrigin->isSameSchemeHostPort(document()->securityOrigin())) {
868             String message = "Unable to post message to " + intendedTargetOrigin->toString() +
869                              ". Recipient has origin " + document()->securityOrigin()->toString() + ".\n";
870             pageConsole()->addMessage(SecurityMessageSource, ErrorMessageLevel, message, stackTrace);
871             return;
872         }
873     }
874
875     dispatchEvent(event);
876 }
877
878 DOMSelection* DOMWindow::getSelection()
879 {
880     if (!isCurrentlyDisplayedInFrame() || !m_frame)
881         return 0;
882
883     return m_frame->document()->getSelection();
884 }
885
886 Element* DOMWindow::frameElement() const
887 {
888     if (!m_frame)
889         return 0;
890
891     return m_frame->ownerElement();
892 }
893
894 void DOMWindow::focus(ScriptExecutionContext* context)
895 {
896     if (!m_frame)
897         return;
898
899     Page* page = m_frame->page();
900     if (!page)
901         return;
902
903     bool allowFocus = WindowFocusAllowedIndicator::windowFocusAllowed() || !m_frame->settings().windowFocusRestricted();
904     if (context) {
905         ASSERT(isMainThread());
906         Document* activeDocument = toDocument(context);
907         if (opener() && opener() != this && activeDocument->domWindow() == opener())
908             allowFocus = true;
909     }
910
911     // If we're a top level window, bring the window to the front.
912     if (m_frame->isMainFrame() && allowFocus)
913         page->chrome().focus();
914
915     if (!m_frame)
916         return;
917
918     // Clear the current frame's focused node if a new frame is about to be focused.
919     Frame* focusedFrame = page->focusController().focusedFrame();
920     if (focusedFrame && focusedFrame != m_frame)
921         focusedFrame->document()->setFocusedElement(0);
922
923     m_frame->eventHandler().focusDocumentView();
924 }
925
926 void DOMWindow::blur()
927 {
928     if (!m_frame)
929         return;
930
931     Page* page = m_frame->page();
932     if (!page)
933         return;
934
935     if (m_frame->settings().windowFocusRestricted())
936         return;
937
938     if (!m_frame->isMainFrame())
939         return;
940
941     page->chrome().unfocus();
942 }
943
944 void DOMWindow::close(ScriptExecutionContext* context)
945 {
946     if (!m_frame)
947         return;
948
949     Page* page = m_frame->page();
950     if (!page)
951         return;
952
953     if (!m_frame->isMainFrame())
954         return;
955
956     if (context) {
957         ASSERT(isMainThread());
958         Document* activeDocument = toDocument(context);
959         if (!activeDocument)
960             return;
961
962         if (!activeDocument->canNavigate(m_frame))
963             return;
964     }
965
966     bool allowScriptsToCloseWindows = m_frame->settings().allowScriptsToCloseWindows();
967
968     if (!(page->openedByDOM() || page->backForward().count() <= 1 || allowScriptsToCloseWindows)) {
969         pageConsole()->addMessage(JSMessageSource, WarningMessageLevel, ASCIILiteral("Can't close the window since it was not opened by JavaScript"));
970         return;
971     }
972
973     if (!m_frame->loader().shouldClose())
974         return;
975
976     page->chrome().closeWindowSoon();
977 }
978
979 void DOMWindow::print()
980 {
981     if (!m_frame)
982         return;
983
984     Page* page = m_frame->page();
985     if (!page)
986         return;
987
988     // Pages are not allowed to bring up a modal print dialog during BeforeUnload dispatch.
989     if (page->isAnyFrameHandlingBeforeUnloadEvent()) {
990         printErrorMessage("Use of window.print is not allowed during beforeunload event dispatch.");
991         return;
992     }
993
994     if (m_frame->loader().activeDocumentLoader()->isLoading()) {
995         m_shouldPrintWhenFinishedLoading = true;
996         return;
997     }
998     m_shouldPrintWhenFinishedLoading = false;
999     page->chrome().print(m_frame);
1000 }
1001
1002 void DOMWindow::stop()
1003 {
1004     if (!m_frame)
1005         return;
1006
1007     // We must check whether the load is complete asynchronously, because we might still be parsing
1008     // the document until the callstack unwinds.
1009     m_frame->loader().stopForUserCancel(true);
1010 }
1011
1012 void DOMWindow::alert(const String& message)
1013 {
1014     if (!m_frame)
1015         return;
1016
1017     // Pages are not allowed to cause modal alerts during BeforeUnload dispatch.
1018     if (page() && page()->isAnyFrameHandlingBeforeUnloadEvent()) {
1019         printErrorMessage("Use of window.alert is not allowed during beforeunload event dispatch.");
1020         return;
1021     }
1022
1023     m_frame->document()->updateStyleIfNeeded();
1024
1025     Page* page = m_frame->page();
1026     if (!page)
1027         return;
1028
1029     page->chrome().runJavaScriptAlert(m_frame, message);
1030 }
1031
1032 bool DOMWindow::confirm(const String& message)
1033 {
1034     if (!m_frame)
1035         return false;
1036     
1037     // Pages are not allowed to cause modal alerts during BeforeUnload dispatch.
1038     if (page() && page()->isAnyFrameHandlingBeforeUnloadEvent()) {
1039         printErrorMessage("Use of window.confirm is not allowed during beforeunload event dispatch.");
1040         return false;
1041     }
1042
1043     m_frame->document()->updateStyleIfNeeded();
1044
1045     Page* page = m_frame->page();
1046     if (!page)
1047         return false;
1048
1049     return page->chrome().runJavaScriptConfirm(m_frame, message);
1050 }
1051
1052 String DOMWindow::prompt(const String& message, const String& defaultValue)
1053 {
1054     if (!m_frame)
1055         return String();
1056
1057     // Pages are not allowed to cause modal alerts during BeforeUnload dispatch.
1058     if (page() && page()->isAnyFrameHandlingBeforeUnloadEvent()) {
1059         printErrorMessage("Use of window.prompt is not allowed during beforeunload event dispatch.");
1060         return String();
1061     }
1062
1063     m_frame->document()->updateStyleIfNeeded();
1064
1065     Page* page = m_frame->page();
1066     if (!page)
1067         return String();
1068
1069     String returnValue;
1070     if (page->chrome().runJavaScriptPrompt(m_frame, message, defaultValue, returnValue))
1071         return returnValue;
1072
1073     return String();
1074 }
1075
1076 String DOMWindow::btoa(const String& stringToEncode, ExceptionCode& ec)
1077 {
1078     if (stringToEncode.isNull())
1079         return String();
1080
1081     if (!stringToEncode.containsOnlyLatin1()) {
1082         ec = INVALID_CHARACTER_ERR;
1083         return String();
1084     }
1085
1086     return base64Encode(stringToEncode.latin1());
1087 }
1088
1089 String DOMWindow::atob(const String& encodedString, ExceptionCode& ec)
1090 {
1091     if (encodedString.isNull())
1092         return String();
1093
1094     if (!encodedString.containsOnlyLatin1()) {
1095         ec = INVALID_CHARACTER_ERR;
1096         return String();
1097     }
1098
1099     Vector<char> out;
1100     if (!base64Decode(encodedString, out, Base64FailOnInvalidCharacterOrExcessPadding)) {
1101         ec = INVALID_CHARACTER_ERR;
1102         return String();
1103     }
1104
1105     return String(out.data(), out.size());
1106 }
1107
1108 bool DOMWindow::find(const String& string, bool caseSensitive, bool backwards, bool wrap, bool /*wholeWord*/, bool /*searchInFrames*/, bool /*showDialog*/) const
1109 {
1110     if (!isCurrentlyDisplayedInFrame())
1111         return false;
1112
1113     // FIXME (13016): Support wholeWord, searchInFrames and showDialog.    
1114     FindOptions options = (backwards ? Backwards : 0) | (caseSensitive ? 0 : CaseInsensitive) | (wrap ? WrapAround : 0);
1115     return m_frame->editor().findString(string, options);
1116 }
1117
1118 bool DOMWindow::offscreenBuffering() const
1119 {
1120     return true;
1121 }
1122
1123 int DOMWindow::outerHeight() const
1124 {
1125     if (!m_frame)
1126         return 0;
1127
1128     Page* page = m_frame->page();
1129     if (!page)
1130         return 0;
1131
1132     return static_cast<int>(page->chrome().windowRect().height());
1133 }
1134
1135 int DOMWindow::outerWidth() const
1136 {
1137     if (!m_frame)
1138         return 0;
1139
1140     Page* page = m_frame->page();
1141     if (!page)
1142         return 0;
1143
1144     return static_cast<int>(page->chrome().windowRect().width());
1145 }
1146
1147 int DOMWindow::innerHeight() const
1148 {
1149     if (!m_frame)
1150         return 0;
1151
1152     FrameView* view = m_frame->view();
1153     if (!view)
1154         return 0;
1155
1156 #if PLATFORM(IOS)
1157     return view->mapFromLayoutToCSSUnits(static_cast<int>(view->actualVisibleContentRect().height()));
1158 #else
1159     return view->mapFromLayoutToCSSUnits(static_cast<int>(view->visibleContentRect(ScrollableArea::IncludeScrollbars).height()));
1160 #endif
1161 }
1162
1163 int DOMWindow::innerWidth() const
1164 {
1165     if (!m_frame)
1166         return 0;
1167
1168     FrameView* view = m_frame->view();
1169     if (!view)
1170         return 0;
1171
1172 #if PLATFORM(IOS)
1173     return view->mapFromLayoutToCSSUnits(static_cast<int>(view->actualVisibleContentRect().width()));
1174 #else
1175     return view->mapFromLayoutToCSSUnits(static_cast<int>(view->visibleContentRect(ScrollableArea::IncludeScrollbars).width()));
1176 #endif
1177 }
1178
1179 int DOMWindow::screenX() const
1180 {
1181     if (!m_frame)
1182         return 0;
1183
1184     Page* page = m_frame->page();
1185     if (!page)
1186         return 0;
1187
1188     return static_cast<int>(page->chrome().windowRect().x());
1189 }
1190
1191 int DOMWindow::screenY() const
1192 {
1193     if (!m_frame)
1194         return 0;
1195
1196     Page* page = m_frame->page();
1197     if (!page)
1198         return 0;
1199
1200     return static_cast<int>(page->chrome().windowRect().y());
1201 }
1202
1203 int DOMWindow::scrollX() const
1204 {
1205     if (!m_frame)
1206         return 0;
1207
1208     FrameView* view = m_frame->view();
1209     if (!view)
1210         return 0;
1211
1212     if (!view->scrollX())
1213         return 0;
1214
1215     m_frame->document()->updateLayoutIgnorePendingStylesheets();
1216
1217 #if PLATFORM(IOS)
1218     return static_cast<int>(view->actualVisibleContentRect().x() / (m_frame->pageZoomFactor() * m_frame->frameScaleFactor()));
1219 #else
1220     return view->mapFromLayoutToCSSUnits(view->scrollX());
1221 #endif
1222 }
1223
1224 int DOMWindow::scrollY() const
1225 {
1226     if (!m_frame)
1227         return 0;
1228
1229     FrameView* view = m_frame->view();
1230     if (!view)
1231         return 0;
1232
1233     if (!view->scrollY())
1234         return 0;
1235
1236     m_frame->document()->updateLayoutIgnorePendingStylesheets();
1237
1238 #if PLATFORM(IOS)
1239     return static_cast<int>(view->actualVisibleContentRect().y() / (m_frame->pageZoomFactor() * m_frame->frameScaleFactor()));
1240 #else
1241     return view->mapFromLayoutToCSSUnits(view->scrollY());
1242 #endif
1243 }
1244
1245 bool DOMWindow::closed() const
1246 {
1247     return !m_frame;
1248 }
1249
1250 unsigned DOMWindow::length() const
1251 {
1252     if (!isCurrentlyDisplayedInFrame())
1253         return 0;
1254
1255     return m_frame->tree().scopedChildCount();
1256 }
1257
1258 String DOMWindow::name() const
1259 {
1260     if (!m_frame)
1261         return String();
1262
1263     return m_frame->tree().name();
1264 }
1265
1266 void DOMWindow::setName(const String& string)
1267 {
1268     if (!m_frame)
1269         return;
1270
1271     m_frame->tree().setName(string);
1272 }
1273
1274 void DOMWindow::setStatus(const String& string) 
1275 {
1276     m_status = string;
1277
1278     if (!m_frame)
1279         return;
1280
1281     Page* page = m_frame->page();
1282     if (!page)
1283         return;
1284
1285     ASSERT(m_frame->document()); // Client calls shouldn't be made when the frame is in inconsistent state.
1286     page->chrome().setStatusbarText(m_frame, m_status);
1287
1288     
1289 void DOMWindow::setDefaultStatus(const String& string) 
1290 {
1291     m_defaultStatus = string;
1292
1293     if (!m_frame)
1294         return;
1295
1296     Page* page = m_frame->page();
1297     if (!page)
1298         return;
1299
1300     ASSERT(m_frame->document()); // Client calls shouldn't be made when the frame is in inconsistent state.
1301     page->chrome().setStatusbarText(m_frame, m_defaultStatus);
1302 }
1303
1304 DOMWindow* DOMWindow::self() const
1305 {
1306     if (!m_frame)
1307         return 0;
1308
1309     return m_frame->document()->domWindow();
1310 }
1311
1312 DOMWindow* DOMWindow::opener() const
1313 {
1314     if (!m_frame)
1315         return 0;
1316
1317     Frame* opener = m_frame->loader().opener();
1318     if (!opener)
1319         return 0;
1320
1321     return opener->document()->domWindow();
1322 }
1323
1324 DOMWindow* DOMWindow::parent() const
1325 {
1326     if (!m_frame)
1327         return 0;
1328
1329     Frame* parent = m_frame->tree().parent();
1330     if (parent)
1331         return parent->document()->domWindow();
1332
1333     return m_frame->document()->domWindow();
1334 }
1335
1336 DOMWindow* DOMWindow::top() const
1337 {
1338     if (!m_frame)
1339         return 0;
1340
1341     Page* page = m_frame->page();
1342     if (!page)
1343         return 0;
1344
1345     return m_frame->tree().top().document()->domWindow();
1346 }
1347
1348 Document* DOMWindow::document() const
1349 {
1350     ScriptExecutionContext* context = ContextDestructionObserver::scriptExecutionContext();
1351     return toDocument(context);
1352 }
1353
1354 PassRefPtr<StyleMedia> DOMWindow::styleMedia() const
1355 {
1356     if (!isCurrentlyDisplayedInFrame())
1357         return 0;
1358     if (!m_media)
1359         m_media = StyleMedia::create(m_frame);
1360     return m_media.get();
1361 }
1362
1363 PassRefPtr<CSSStyleDeclaration> DOMWindow::getComputedStyle(Element* elt, const String& pseudoElt) const
1364 {
1365     if (!elt)
1366         return 0;
1367
1368     return CSSComputedStyleDeclaration::create(elt, false, pseudoElt);
1369 }
1370
1371 PassRefPtr<CSSRuleList> DOMWindow::getMatchedCSSRules(Element* element, const String& pseudoElement, bool authorOnly) const
1372 {
1373     if (!isCurrentlyDisplayedInFrame())
1374         return 0;
1375
1376     unsigned colonStart = pseudoElement[0] == ':' ? (pseudoElement[1] == ':' ? 2 : 1) : 0;
1377     CSSSelector::PseudoType pseudoType = CSSSelector::parsePseudoType(AtomicString(pseudoElement.substring(colonStart)));
1378     if (pseudoType == CSSSelector::PseudoUnknown && !pseudoElement.isEmpty())
1379         return 0;
1380
1381     unsigned rulesToInclude = StyleResolver::AuthorCSSRules;
1382     if (!authorOnly)
1383         rulesToInclude |= StyleResolver::UAAndUserCSSRules;
1384     if (m_frame->settings().crossOriginCheckInGetMatchedCSSRulesDisabled())
1385         rulesToInclude |= StyleResolver::CrossOriginCSSRules;
1386
1387     PseudoId pseudoId = CSSSelector::pseudoId(pseudoType);
1388
1389     Vector<RefPtr<StyleRuleBase>> matchedRules = m_frame->document()->ensureStyleResolver().pseudoStyleRulesForElement(element, pseudoId, rulesToInclude);
1390     if (matchedRules.isEmpty())
1391         return 0;
1392
1393     RefPtr<StaticCSSRuleList> ruleList = StaticCSSRuleList::create();
1394     for (unsigned i = 0; i < matchedRules.size(); ++i)
1395         ruleList->rules().append(matchedRules[i]->createCSSOMWrapper());
1396
1397     return ruleList.release();
1398 }
1399
1400 PassRefPtr<WebKitPoint> DOMWindow::webkitConvertPointFromNodeToPage(Node* node, const WebKitPoint* p) const
1401 {
1402     if (!node || !p)
1403         return 0;
1404
1405     if (!document())
1406         return 0;
1407
1408     document()->updateLayoutIgnorePendingStylesheets();
1409
1410     FloatPoint pagePoint(p->x(), p->y());
1411     pagePoint = node->convertToPage(pagePoint);
1412     return WebKitPoint::create(pagePoint.x(), pagePoint.y());
1413 }
1414
1415 PassRefPtr<WebKitPoint> DOMWindow::webkitConvertPointFromPageToNode(Node* node, const WebKitPoint* p) const
1416 {
1417     if (!node || !p)
1418         return 0;
1419
1420     if (!document())
1421         return 0;
1422
1423     document()->updateLayoutIgnorePendingStylesheets();
1424
1425     FloatPoint nodePoint(p->x(), p->y());
1426     nodePoint = node->convertFromPage(nodePoint);
1427     return WebKitPoint::create(nodePoint.x(), nodePoint.y());
1428 }
1429
1430 double DOMWindow::devicePixelRatio() const
1431 {
1432     if (!m_frame)
1433         return 0.0;
1434
1435     Page* page = m_frame->page();
1436     if (!page)
1437         return 0.0;
1438
1439     return page->deviceScaleFactor();
1440 }
1441
1442 void DOMWindow::scrollBy(int x, int y) const
1443 {
1444     if (!isCurrentlyDisplayedInFrame())
1445         return;
1446
1447     document()->updateLayoutIgnorePendingStylesheets();
1448
1449     FrameView* view = m_frame->view();
1450     if (!view)
1451         return;
1452
1453     IntSize scaledOffset(view->mapFromCSSToLayoutUnits(x), view->mapFromCSSToLayoutUnits(y));
1454 #if PLATFORM(IOS)
1455     view->setActualScrollPosition(view->actualVisibleContentRect().location() + scaledOffset);
1456 #else
1457     view->scrollBy(scaledOffset);
1458 #endif
1459 }
1460
1461 void DOMWindow::scrollTo(int x, int y) const
1462 {
1463     if (!isCurrentlyDisplayedInFrame())
1464         return;
1465
1466     document()->updateLayoutIgnorePendingStylesheets();
1467
1468     RefPtr<FrameView> view = m_frame->view();
1469     if (!view)
1470         return;
1471
1472
1473 #if PLATFORM(IOS)
1474     int zoomedX = static_cast<int>(x * m_frame->pageZoomFactor() * m_frame->frameScaleFactor());
1475     int zoomedY = static_cast<int>(y * m_frame->pageZoomFactor() * m_frame->frameScaleFactor());
1476     view->setActualScrollPosition(IntPoint(zoomedX, zoomedY));
1477 #else
1478     IntPoint layoutPos(view->mapFromCSSToLayoutUnits(x), view->mapFromCSSToLayoutUnits(y));
1479     view->setScrollPosition(layoutPos);
1480 #endif
1481 }
1482
1483 bool DOMWindow::allowedToChangeWindowGeometry() const
1484 {
1485     if (!m_frame)
1486         return false;
1487     if (!m_frame->page())
1488         return false;
1489     if (!m_frame->isMainFrame())
1490         return false;
1491     // Prevent web content from tricking the user into initiating a drag.
1492     if (m_frame->eventHandler().mousePressed())
1493         return false;
1494     return true;
1495 }
1496
1497 void DOMWindow::moveBy(float x, float y) const
1498 {
1499     if (!allowedToChangeWindowGeometry())
1500         return;
1501
1502     Page* page = m_frame->page();
1503     FloatRect fr = page->chrome().windowRect();
1504     FloatRect update = fr;
1505     update.move(x, y);
1506     // Security check (the spec talks about UniversalBrowserWrite to disable this check...)
1507     page->chrome().setWindowRect(adjustWindowRect(page, update));
1508 }
1509
1510 void DOMWindow::moveTo(float x, float y) const
1511 {
1512     if (!allowedToChangeWindowGeometry())
1513         return;
1514
1515     Page* page = m_frame->page();
1516     FloatRect fr = page->chrome().windowRect();
1517     FloatRect sr = screenAvailableRect(page->mainFrame().view());
1518     fr.setLocation(sr.location());
1519     FloatRect update = fr;
1520     update.move(x, y);
1521     // Security check (the spec talks about UniversalBrowserWrite to disable this check...)
1522     page->chrome().setWindowRect(adjustWindowRect(page, update));
1523 }
1524
1525 void DOMWindow::resizeBy(float x, float y) const
1526 {
1527     if (!allowedToChangeWindowGeometry())
1528         return;
1529
1530     Page* page = m_frame->page();
1531     FloatRect fr = page->chrome().windowRect();
1532     FloatSize dest = fr.size() + FloatSize(x, y);
1533     FloatRect update(fr.location(), dest);
1534     page->chrome().setWindowRect(adjustWindowRect(page, update));
1535 }
1536
1537 void DOMWindow::resizeTo(float width, float height) const
1538 {
1539     if (!allowedToChangeWindowGeometry())
1540         return;
1541
1542     Page* page = m_frame->page();
1543     FloatRect fr = page->chrome().windowRect();
1544     FloatSize dest = FloatSize(width, height);
1545     FloatRect update(fr.location(), dest);
1546     page->chrome().setWindowRect(adjustWindowRect(page, update));
1547 }
1548
1549 int DOMWindow::setTimeout(PassOwnPtr<ScheduledAction> action, int timeout, ExceptionCode& ec)
1550 {
1551     ScriptExecutionContext* context = scriptExecutionContext();
1552     if (!context) {
1553         ec = INVALID_ACCESS_ERR;
1554         return -1;
1555     }
1556     return DOMTimer::install(context, action, timeout, true);
1557 }
1558
1559 void DOMWindow::clearTimeout(int timeoutId)
1560 {
1561 #if PLATFORM(IOS)
1562     if (m_frame) {
1563         Document* document = m_frame->document();
1564         if (timeoutId > 0 && document) {
1565             DOMTimer* timer = document->findTimeout(timeoutId);
1566             if (timer && WebThreadContainsObservedContentModifier(timer)) {
1567                 WebThreadRemoveObservedContentModifier(timer);
1568
1569                 if (!WebThreadCountOfObservedContentModifiers()) {
1570                     if (Page* page = m_frame->page())
1571                         page->chrome().client().observedContentChange(m_frame);
1572                 }
1573             }
1574         }
1575     }
1576 #endif
1577     ScriptExecutionContext* context = scriptExecutionContext();
1578     if (!context)
1579         return;
1580     DOMTimer::removeById(context, timeoutId);
1581 }
1582
1583 int DOMWindow::setInterval(PassOwnPtr<ScheduledAction> action, int timeout, ExceptionCode& ec)
1584 {
1585     ScriptExecutionContext* context = scriptExecutionContext();
1586     if (!context) {
1587         ec = INVALID_ACCESS_ERR;
1588         return -1;
1589     }
1590     return DOMTimer::install(context, action, timeout, false);
1591 }
1592
1593 void DOMWindow::clearInterval(int timeoutId)
1594 {
1595     ScriptExecutionContext* context = scriptExecutionContext();
1596     if (!context)
1597         return;
1598     DOMTimer::removeById(context, timeoutId);
1599 }
1600
1601 #if ENABLE(REQUEST_ANIMATION_FRAME)
1602 int DOMWindow::requestAnimationFrame(PassRefPtr<RequestAnimationFrameCallback> callback)
1603 {
1604     callback->m_useLegacyTimeBase = false;
1605     if (Document* d = document())
1606         return d->requestAnimationFrame(callback);
1607     return 0;
1608 }
1609
1610 int DOMWindow::webkitRequestAnimationFrame(PassRefPtr<RequestAnimationFrameCallback> callback)
1611 {
1612     callback->m_useLegacyTimeBase = true;
1613     if (Document* d = document())
1614         return d->requestAnimationFrame(callback);
1615     return 0;
1616 }
1617
1618 void DOMWindow::cancelAnimationFrame(int id)
1619 {
1620     if (Document* d = document())
1621         d->cancelAnimationFrame(id);
1622 }
1623 #endif
1624
1625 #if ENABLE(CSS3_CONDITIONAL_RULES)
1626 DOMWindowCSS* DOMWindow::css()
1627 {
1628     if (!m_css)
1629         m_css = DOMWindowCSS::create();
1630     return m_css.get();
1631 }
1632 #endif
1633
1634 static void didAddStorageEventListener(DOMWindow* window)
1635 {
1636     // Creating these WebCore::Storage objects informs the system that we'd like to receive
1637     // notifications about storage events that might be triggered in other processes. Rather
1638     // than subscribe to these notifications explicitly, we subscribe to them implicitly to
1639     // simplify the work done by the system. 
1640     window->localStorage(IGNORE_EXCEPTION);
1641     window->sessionStorage(IGNORE_EXCEPTION);
1642 }
1643
1644 bool DOMWindow::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
1645 {
1646     if (!EventTarget::addEventListener(eventType, listener, useCapture))
1647         return false;
1648
1649     if (Document* document = this->document()) {
1650         document->addListenerTypeIfNeeded(eventType);
1651         if (eventType == eventNames().wheelEvent || eventType == eventNames().mousewheelEvent)
1652             document->didAddWheelEventHandler();
1653         else if (eventNames().isTouchEventType(eventType))
1654             document->didAddTouchEventHandler(document);
1655         else if (eventType == eventNames().storageEvent)
1656             didAddStorageEventListener(this);
1657     }
1658
1659     if (eventType == eventNames().unloadEvent)
1660         addUnloadEventListener(this);
1661     else if (eventType == eventNames().beforeunloadEvent && allowsBeforeUnloadListeners(this))
1662         addBeforeUnloadEventListener(this);
1663 #if ENABLE(DEVICE_ORIENTATION)
1664 #if PLATFORM(IOS)
1665     else if (eventType == eventNames().devicemotionEvent && document())
1666         document()->deviceMotionController()->addDeviceEventListener(this);
1667     else if (eventType == eventNames().deviceorientationEvent && document())
1668         document()->deviceOrientationController()->addDeviceEventListener(this);
1669 #else
1670     else if (eventType == eventNames().devicemotionEvent && RuntimeEnabledFeatures::sharedFeatures().deviceMotionEnabled()) {
1671         if (DeviceMotionController* controller = DeviceMotionController::from(page()))
1672             controller->addDeviceEventListener(this);
1673     } else if (eventType == eventNames().deviceorientationEvent && RuntimeEnabledFeatures::sharedFeatures().deviceOrientationEnabled()) {
1674         if (DeviceOrientationController* controller = DeviceOrientationController::from(page()))
1675             controller->addDeviceEventListener(this);
1676     }
1677 #endif // PLATFORM(IOS)
1678 #endif // ENABLE(DEVICE_ORIENTATION)
1679 #if PLATFORM(IOS)
1680     else if (eventType == eventNames().scrollEvent)
1681         incrementScrollEventListenersCount();
1682 #endif
1683 #if ENABLE(IOS_TOUCH_EVENTS)
1684     else if (eventNames().isTouchEventType(eventType))
1685         ++m_touchEventListenerCount;
1686 #endif
1687 #if ENABLE(IOS_GESTURE_EVENTS)
1688     else if (eventNames().isGestureEventType(eventType))
1689         ++m_touchEventListenerCount;
1690 #endif
1691
1692 #if ENABLE(PROXIMITY_EVENTS)
1693     else if (eventType == eventNames().webkitdeviceproximityEvent) {
1694         if (DeviceProximityController* controller = DeviceProximityController::from(page()))
1695             controller->addDeviceEventListener(this);
1696     }
1697 #endif
1698
1699     return true;
1700 }
1701
1702 #if PLATFORM(IOS)
1703 void DOMWindow::incrementScrollEventListenersCount()
1704 {
1705     Document* document = this->document();
1706     if (++m_scrollEventListenerCount == 1 && document == document->topDocument()) {
1707         Frame* frame = this->frame();
1708         if (frame && frame->page())
1709             frame->page()->chrome().client().setNeedsScrollNotifications(frame, true);
1710     }
1711 }
1712
1713 void DOMWindow::decrementScrollEventListenersCount()
1714 {
1715     Document* document = this->document();
1716     if (!--m_scrollEventListenerCount && document == document->topDocument()) {
1717         Frame* frame = this->frame();
1718         if (frame && frame->page() && !document->inPageCache())
1719             frame->page()->chrome().client().setNeedsScrollNotifications(frame, false);
1720     }
1721 }
1722 #endif
1723
1724 void DOMWindow::resetAllGeolocationPermission()
1725 {
1726     // FIXME: Remove PLATFORM(IOS)-guard once we upstream the iOS changes to Geolocation.cpp.
1727 #if ENABLE(GEOLOCATION) && PLATFORM(IOS)
1728     if (m_navigator)
1729         NavigatorGeolocation::from(m_navigator.get())->resetAllGeolocationPermission();
1730 #endif
1731 }
1732
1733 bool DOMWindow::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
1734 {
1735     if (!EventTarget::removeEventListener(eventType, listener, useCapture))
1736         return false;
1737
1738     if (Document* document = this->document()) {
1739         if (eventType == eventNames().wheelEvent || eventType == eventNames().mousewheelEvent)
1740             document->didRemoveWheelEventHandler();
1741         else if (eventNames().isTouchEventType(eventType))
1742             document->didRemoveTouchEventHandler(document);
1743     }
1744
1745     if (eventType == eventNames().unloadEvent)
1746         removeUnloadEventListener(this);
1747     else if (eventType == eventNames().beforeunloadEvent && allowsBeforeUnloadListeners(this))
1748         removeBeforeUnloadEventListener(this);
1749 #if ENABLE(DEVICE_ORIENTATION)
1750 #if PLATFORM(IOS)
1751     else if (eventType == eventNames().devicemotionEvent && document())
1752         document()->deviceMotionController()->removeDeviceEventListener(this);
1753     else if (eventType == eventNames().deviceorientationEvent && document())
1754         document()->deviceOrientationController()->removeDeviceEventListener(this);
1755 #else
1756     else if (eventType == eventNames().devicemotionEvent) {
1757         if (DeviceMotionController* controller = DeviceMotionController::from(page()))
1758             controller->removeDeviceEventListener(this);
1759     } else if (eventType == eventNames().deviceorientationEvent) {
1760         if (DeviceOrientationController* controller = DeviceOrientationController::from(page()))
1761             controller->removeDeviceEventListener(this);
1762     }
1763 #endif // PLATFORM(IOS)
1764 #endif // ENABLE(DEVICE_ORIENTATION)
1765 #if PLATFORM(IOS)
1766     else if (eventType == eventNames().scrollEvent)
1767         decrementScrollEventListenersCount();
1768 #endif
1769 #if ENABLE(IOS_TOUCH_EVENTS)
1770     else if (eventNames().isTouchEventType(eventType)) {
1771         ASSERT(m_touchEventListenerCount > 0);
1772         --m_touchEventListenerCount;
1773     }
1774 #endif
1775 #if ENABLE(IOS_GESTURE_EVENTS)
1776     else if (eventNames().isGestureEventType(eventType)) {
1777         ASSERT(m_touchEventListenerCount > 0);
1778         --m_touchEventListenerCount;
1779     }
1780 #endif
1781
1782 #if ENABLE(PROXIMITY_EVENTS)
1783     else if (eventType == eventNames().webkitdeviceproximityEvent) {
1784         if (DeviceProximityController* controller = DeviceProximityController::from(page()))
1785             controller->removeDeviceEventListener(this);
1786     }
1787 #endif
1788
1789     return true;
1790 }
1791
1792 void DOMWindow::dispatchLoadEvent()
1793 {
1794     RefPtr<Event> loadEvent(Event::create(eventNames().loadEvent, false, false));
1795     if (m_frame && m_frame->loader().documentLoader() && !m_frame->loader().documentLoader()->timing()->loadEventStart()) {
1796         // The DocumentLoader (and thus its DocumentLoadTiming) might get destroyed while dispatching
1797         // the event, so protect it to prevent writing the end time into freed memory.
1798         RefPtr<DocumentLoader> documentLoader = m_frame->loader().documentLoader();
1799         DocumentLoadTiming* timing = documentLoader->timing();
1800         timing->markLoadEventStart();
1801         dispatchEvent(loadEvent, document());
1802         timing->markLoadEventEnd();
1803     } else
1804         dispatchEvent(loadEvent, document());
1805
1806     // For load events, send a separate load event to the enclosing frame only.
1807     // This is a DOM extension and is independent of bubbling/capturing rules of
1808     // the DOM.
1809     Element* ownerElement = m_frame ? m_frame->ownerElement() : 0;
1810     if (ownerElement)
1811         ownerElement->dispatchEvent(Event::create(eventNames().loadEvent, false, false));
1812
1813     InspectorInstrumentation::loadEventFired(frame());
1814 }
1815
1816 bool DOMWindow::dispatchEvent(PassRefPtr<Event> prpEvent, PassRefPtr<EventTarget> prpTarget)
1817 {
1818     Ref<EventTarget> protect(*this);
1819     RefPtr<Event> event = prpEvent;
1820
1821     // Pausing a page may trigger pagehide and pageshow events. WebCore also implicitly fires these
1822     // events when closing a WebView. Here we keep track of the state of the page to prevent duplicate,
1823     // unbalanced events per the definition of the pageshow event:
1824     // <http://www.whatwg.org/specs/web-apps/current-work/multipage/history.html#event-pageshow>.
1825     if (event->eventInterface() == PageTransitionEventInterfaceType) {
1826         if (event->type() == eventNames().pageshowEvent) {
1827             if (m_lastPageStatus == PageStatusShown)
1828                 return true; // Event was previously dispatched; do not fire a duplicate event.
1829             m_lastPageStatus = PageStatusShown;
1830         } else if (event->type() == eventNames().pagehideEvent) {
1831             if (m_lastPageStatus == PageStatusHidden)
1832                 return true; // Event was previously dispatched; do not fire a duplicate event.
1833             m_lastPageStatus = PageStatusHidden;
1834         }
1835     }
1836
1837     event->setTarget(prpTarget ? prpTarget : this);
1838     event->setCurrentTarget(this);
1839     event->setEventPhase(Event::AT_TARGET);
1840
1841     InspectorInstrumentationCookie cookie = InspectorInstrumentation::willDispatchEventOnWindow(frame(), *event, this);
1842
1843     bool result = fireEventListeners(event.get());
1844
1845     InspectorInstrumentation::didDispatchEventOnWindow(cookie);
1846
1847     return result;
1848 }
1849
1850 void DOMWindow::removeAllEventListeners()
1851 {
1852     EventTarget::removeAllEventListeners();
1853
1854 #if ENABLE(DEVICE_ORIENTATION)
1855 #if PLATFORM(IOS)
1856     if (Document* document = this->document()) {
1857         document->deviceMotionController()->removeAllDeviceEventListeners(this);
1858         document->deviceOrientationController()->removeAllDeviceEventListeners(this);
1859     }
1860 #else
1861     if (DeviceMotionController* controller = DeviceMotionController::from(page()))
1862         controller->removeAllDeviceEventListeners(this);
1863     if (DeviceOrientationController* controller = DeviceOrientationController::from(page()))
1864         controller->removeAllDeviceEventListeners(this);
1865 #endif // PLATFORM(IOS)
1866 #endif // ENABLE(DEVICE_ORIENTATION)
1867
1868 #if PLATFORM(IOS)
1869     if (m_scrollEventListenerCount) {
1870         m_scrollEventListenerCount = 1;
1871         decrementScrollEventListenersCount();
1872     }
1873 #endif
1874
1875 #if ENABLE(IOS_TOUCH_EVENTS) || ENABLE(IOS_GESTURE_EVENTS)
1876     m_touchEventListenerCount = 0;
1877 #endif
1878
1879 #if ENABLE(TOUCH_EVENTS)
1880     if (Document* document = this->document())
1881         document->didRemoveEventTargetNode(document);
1882 #endif
1883
1884 #if ENABLE(PROXIMITY_EVENTS)
1885     if (DeviceProximityController* controller = DeviceProximityController::from(page()))
1886         controller->removeAllDeviceEventListeners(this);
1887 #endif
1888
1889     removeAllUnloadEventListeners(this);
1890     removeAllBeforeUnloadEventListeners(this);
1891 }
1892
1893 void DOMWindow::captureEvents()
1894 {
1895     // Not implemented.
1896 }
1897
1898 void DOMWindow::releaseEvents()
1899 {
1900     // Not implemented.
1901 }
1902
1903 void DOMWindow::finishedLoading()
1904 {
1905     if (m_shouldPrintWhenFinishedLoading) {
1906         m_shouldPrintWhenFinishedLoading = false;
1907         print();
1908     }
1909 }
1910
1911 void DOMWindow::setLocation(const String& urlString, DOMWindow& activeWindow, DOMWindow& firstWindow, SetLocationLocking locking)
1912 {
1913     if (!isCurrentlyDisplayedInFrame())
1914         return;
1915
1916     Document* activeDocument = activeWindow.document();
1917     if (!activeDocument)
1918         return;
1919
1920     if (!activeDocument->canNavigate(m_frame))
1921         return;
1922
1923     Frame* firstFrame = firstWindow.frame();
1924     if (!firstFrame)
1925         return;
1926
1927     URL completedURL = firstFrame->document()->completeURL(urlString);
1928     if (completedURL.isNull())
1929         return;
1930
1931     if (isInsecureScriptAccess(activeWindow, completedURL))
1932         return;
1933
1934     // We want a new history item if we are processing a user gesture.
1935     m_frame->navigationScheduler().scheduleLocationChange(activeDocument->securityOrigin(),
1936         // FIXME: What if activeDocument()->frame() is 0?
1937         completedURL, activeDocument->frame()->loader().outgoingReferrer(),
1938         locking != LockHistoryBasedOnGestureState || !ScriptController::processingUserGesture(),
1939         locking != LockHistoryBasedOnGestureState);
1940 }
1941
1942 void DOMWindow::printErrorMessage(const String& message)
1943 {
1944     if (message.isEmpty())
1945         return;
1946
1947     pageConsole()->addMessage(JSMessageSource, ErrorMessageLevel, message);
1948 }
1949
1950 String DOMWindow::crossDomainAccessErrorMessage(const DOMWindow& activeWindow)
1951 {
1952     const URL& activeWindowURL = activeWindow.document()->url();
1953     if (activeWindowURL.isNull())
1954         return String();
1955
1956     ASSERT(!activeWindow.document()->securityOrigin()->canAccess(document()->securityOrigin()));
1957
1958     // FIXME: This message, and other console messages, have extra newlines. Should remove them.
1959     SecurityOrigin* activeOrigin = activeWindow.document()->securityOrigin();
1960     SecurityOrigin* targetOrigin = document()->securityOrigin();
1961     String message = "Blocked a frame with origin \"" + activeOrigin->toString() + "\" from accessing a frame with origin \"" + targetOrigin->toString() + "\". ";
1962
1963     // Sandbox errors: Use the origin of the frames' location, rather than their actual origin (since we know that at least one will be "null").
1964     URL activeURL = activeWindow.document()->url();
1965     URL targetURL = document()->url();
1966     if (document()->isSandboxed(SandboxOrigin) || activeWindow.document()->isSandboxed(SandboxOrigin)) {
1967         message = "Blocked a frame at \"" + SecurityOrigin::create(activeURL)->toString() + "\" from accessing a frame at \"" + SecurityOrigin::create(targetURL)->toString() + "\". ";
1968         if (document()->isSandboxed(SandboxOrigin) && activeWindow.document()->isSandboxed(SandboxOrigin))
1969             return "Sandbox access violation: " + message + " Both frames are sandboxed and lack the \"allow-same-origin\" flag.";
1970         if (document()->isSandboxed(SandboxOrigin))
1971             return "Sandbox access violation: " + message + " The frame being accessed is sandboxed and lacks the \"allow-same-origin\" flag.";
1972         return "Sandbox access violation: " + message + " The frame requesting access is sandboxed and lacks the \"allow-same-origin\" flag.";
1973     }
1974
1975     // Protocol errors: Use the URL's protocol rather than the origin's protocol so that we get a useful message for non-heirarchal URLs like 'data:'.
1976     if (targetOrigin->protocol() != activeOrigin->protocol())
1977         return message + " The frame requesting access has a protocol of \"" + activeURL.protocol() + "\", the frame being accessed has a protocol of \"" + targetURL.protocol() + "\". Protocols must match.\n";
1978
1979     // 'document.domain' errors.
1980     if (targetOrigin->domainWasSetInDOM() && activeOrigin->domainWasSetInDOM())
1981         return message + "The frame requesting access set \"document.domain\" to \"" + activeOrigin->domain() + "\", the frame being accessed set it to \"" + targetOrigin->domain() + "\". Both must set \"document.domain\" to the same value to allow access.";
1982     if (activeOrigin->domainWasSetInDOM())
1983         return message + "The frame requesting access set \"document.domain\" to \"" + activeOrigin->domain() + "\", but the frame being accessed did not. Both must set \"document.domain\" to the same value to allow access.";
1984     if (targetOrigin->domainWasSetInDOM())
1985         return message + "The frame being accessed set \"document.domain\" to \"" + targetOrigin->domain() + "\", but the frame requesting access did not. Both must set \"document.domain\" to the same value to allow access.";
1986
1987     // Default.
1988     return message + "Protocols, domains, and ports must match.";
1989 }
1990
1991 bool DOMWindow::isInsecureScriptAccess(DOMWindow& activeWindow, const String& urlString)
1992 {
1993     if (!protocolIsJavaScript(urlString))
1994         return false;
1995
1996     // If this DOMWindow isn't currently active in the Frame, then there's no
1997     // way we should allow the access.
1998     // FIXME: Remove this check if we're able to disconnect DOMWindow from
1999     // Frame on navigation: https://bugs.webkit.org/show_bug.cgi?id=62054
2000     if (isCurrentlyDisplayedInFrame()) {
2001         // FIXME: Is there some way to eliminate the need for a separate "activeWindow == this" check?
2002         if (&activeWindow == this)
2003             return false;
2004
2005         // FIXME: The name canAccess seems to be a roundabout way to ask "can execute script".
2006         // Can we name the SecurityOrigin function better to make this more clear?
2007         if (activeWindow.document()->securityOrigin()->canAccess(document()->securityOrigin()))
2008             return false;
2009     }
2010
2011     printErrorMessage(crossDomainAccessErrorMessage(activeWindow));
2012     return true;
2013 }
2014
2015 PassRefPtr<Frame> DOMWindow::createWindow(const String& urlString, const AtomicString& frameName, const WindowFeatures& windowFeatures,
2016     DOMWindow& activeWindow, Frame* firstFrame, Frame* openerFrame, PrepareDialogFunction function, void* functionContext)
2017 {
2018     Frame* activeFrame = activeWindow.frame();
2019
2020     URL completedURL = urlString.isEmpty() ? URL(ParsedURLString, emptyString()) : firstFrame->document()->completeURL(urlString);
2021     if (!completedURL.isEmpty() && !completedURL.isValid()) {
2022         // Don't expose client code to invalid URLs.
2023         activeWindow.printErrorMessage("Unable to open a window with invalid URL '" + completedURL.string() + "'.\n");
2024         return 0;
2025     }
2026
2027     // For whatever reason, Firefox uses the first frame to determine the outgoingReferrer. We replicate that behavior here.
2028     String referrer = SecurityPolicy::generateReferrerHeader(firstFrame->document()->referrerPolicy(), completedURL, firstFrame->loader().outgoingReferrer());
2029
2030     ResourceRequest request(completedURL, referrer);
2031     FrameLoader::addHTTPOriginIfNeeded(request, firstFrame->loader().outgoingOrigin());
2032     FrameLoadRequest frameRequest(activeWindow.document()->securityOrigin(), request, frameName);
2033
2034     // We pass the opener frame for the lookupFrame in case the active frame is different from
2035     // the opener frame, and the name references a frame relative to the opener frame.
2036     bool created;
2037     RefPtr<Frame> newFrame = WebCore::createWindow(activeFrame, openerFrame, frameRequest, windowFeatures, created);
2038     if (!newFrame)
2039         return 0;
2040
2041     newFrame->loader().setOpener(openerFrame);
2042     newFrame->page()->setOpenedByDOM();
2043
2044     if (newFrame->document()->domWindow()->isInsecureScriptAccess(activeWindow, completedURL))
2045         return newFrame.release();
2046
2047     if (function)
2048         function(newFrame->document()->domWindow(), functionContext);
2049
2050     if (created)
2051         newFrame->loader().changeLocation(activeWindow.document()->securityOrigin(), completedURL, referrer, false, false);
2052     else if (!urlString.isEmpty()) {
2053         bool lockHistory = !ScriptController::processingUserGesture();
2054         newFrame->navigationScheduler().scheduleLocationChange(activeWindow.document()->securityOrigin(), completedURL.string(), referrer, lockHistory, false);
2055     }
2056
2057     // Navigating the new frame could result in it being detached from its page by a navigation policy delegate.
2058     if (!newFrame->page())
2059         return 0;
2060
2061     return newFrame.release();
2062 }
2063
2064 PassRefPtr<DOMWindow> DOMWindow::open(const String& urlString, const AtomicString& frameName, const String& windowFeaturesString,
2065     DOMWindow& activeWindow, DOMWindow& firstWindow)
2066 {
2067     if (!isCurrentlyDisplayedInFrame())
2068         return 0;
2069     Document* activeDocument = activeWindow.document();
2070     if (!activeDocument)
2071         return 0;
2072     Frame* firstFrame = firstWindow.frame();
2073     if (!firstFrame)
2074         return 0;
2075
2076     if (!firstWindow.allowPopUp()) {
2077         // Because FrameTree::find() returns true for empty strings, we must check for empty frame names.
2078         // Otherwise, illegitimate window.open() calls with no name will pass right through the popup blocker.
2079         if (frameName.isEmpty() || !m_frame->tree().find(frameName))
2080             return 0;
2081     }
2082
2083     // Get the target frame for the special cases of _top and _parent.
2084     // In those cases, we schedule a location change right now and return early.
2085     Frame* targetFrame = 0;
2086     if (frameName == "_top")
2087         targetFrame = &m_frame->tree().top();
2088     else if (frameName == "_parent") {
2089         if (Frame* parent = m_frame->tree().parent())
2090             targetFrame = parent;
2091         else
2092             targetFrame = m_frame;
2093     }
2094     if (targetFrame) {
2095         if (!activeDocument->canNavigate(targetFrame))
2096             return 0;
2097
2098         URL completedURL = firstFrame->document()->completeURL(urlString);
2099
2100         if (targetFrame->document()->domWindow()->isInsecureScriptAccess(activeWindow, completedURL))
2101             return targetFrame->document()->domWindow();
2102
2103         if (urlString.isEmpty())
2104             return targetFrame->document()->domWindow();
2105
2106         // For whatever reason, Firefox uses the first window rather than the active window to
2107         // determine the outgoing referrer. We replicate that behavior here.
2108         bool lockHistory = !ScriptController::processingUserGesture();
2109         targetFrame->navigationScheduler().scheduleLocationChange(
2110             activeDocument->securityOrigin(),
2111             completedURL,
2112             firstFrame->loader().outgoingReferrer(),
2113             lockHistory,
2114             false);
2115         return targetFrame->document()->domWindow();
2116     }
2117
2118     WindowFeatures windowFeatures(windowFeaturesString);
2119     RefPtr<Frame> result = createWindow(urlString, frameName, windowFeatures, activeWindow, firstFrame, m_frame);
2120     return result ? result->document()->domWindow() : 0;
2121 }
2122
2123 void DOMWindow::showModalDialog(const String& urlString, const String& dialogFeaturesString,
2124     DOMWindow& activeWindow, DOMWindow& firstWindow, PrepareDialogFunction function, void* functionContext)
2125 {
2126     if (!isCurrentlyDisplayedInFrame())
2127         return;
2128     Frame* activeFrame = activeWindow.frame();
2129     if (!activeFrame)
2130         return;
2131     Frame* firstFrame = firstWindow.frame();
2132     if (!firstFrame)
2133         return;
2134
2135     // Pages are not allowed to cause modal alerts during BeforeUnload dispatch.
2136     if (page() && page()->isAnyFrameHandlingBeforeUnloadEvent()) {
2137         printErrorMessage("Use of window.showModalDialog is not allowed during beforeunload event dispatch.");
2138         return;
2139     }
2140
2141     if (!canShowModalDialogNow(m_frame) || !firstWindow.allowPopUp())
2142         return;
2143
2144     WindowFeatures windowFeatures(dialogFeaturesString, screenAvailableRect(m_frame->view()));
2145     RefPtr<Frame> dialogFrame = createWindow(urlString, emptyAtom, windowFeatures,
2146         activeWindow, firstFrame, m_frame, function, functionContext);
2147     if (!dialogFrame)
2148         return;
2149     dialogFrame->page()->chrome().runModal();
2150 }
2151
2152 void DOMWindow::enableSuddenTermination()
2153 {
2154     if (Page* page = this->page())
2155         page->chrome().enableSuddenTermination();
2156 }
2157
2158 void DOMWindow::disableSuddenTermination()
2159 {
2160     if (Page* page = this->page())
2161         page->chrome().disableSuddenTermination();
2162 }
2163
2164 } // namespace WebCore