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