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