08bf90986634657cd4742769dd8b4b11de8a8641
[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 "PageConsoleClient.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 ENABLE(GAMEPAD)
128 #include "GamepadManager.h"
129 #endif
130
131 #if PLATFORM(IOS)
132 #if ENABLE(GEOLOCATION)
133 #include "NavigatorGeolocation.h"
134 #endif
135 #include "WKContentObservation.h"
136 #endif
137
138 using namespace Inspector;
139
140 namespace WebCore {
141
142 class PostMessageTimer : public TimerBase {
143 public:
144     PostMessageTimer(DOMWindow* window, PassRefPtr<SerializedScriptValue> message, const String& sourceOrigin, PassRefPtr<DOMWindow> source, std::unique_ptr<MessagePortChannelArray> channels, SecurityOrigin* targetOrigin, PassRefPtr<ScriptCallStack> stackTrace)
145         : m_window(window)
146         , m_message(message)
147         , m_origin(sourceOrigin)
148         , m_source(source)
149         , m_channels(WTF::move(channels))
150         , m_targetOrigin(targetOrigin)
151         , m_stackTrace(stackTrace)
152     {
153     }
154
155     PassRefPtr<MessageEvent> event(ScriptExecutionContext* context)
156     {
157         std::unique_ptr<MessagePortArray> messagePorts = MessagePort::entanglePorts(*context, WTF::move(m_channels));
158         return MessageEvent::create(WTF::move(messagePorts), m_message, m_origin, String(), m_source);
159     }
160     SecurityOrigin* targetOrigin() const { return m_targetOrigin.get(); }
161     ScriptCallStack* stackTrace() const { return m_stackTrace.get(); }
162
163 private:
164     virtual void fired()
165     {
166         // This object gets deleted when std::unique_ptr falls out of scope..
167         std::unique_ptr<PostMessageTimer> timer(this);
168         m_window->postMessageTimerFired(*timer);
169     }
170
171     RefPtr<DOMWindow> m_window;
172     RefPtr<SerializedScriptValue> m_message;
173     String m_origin;
174     RefPtr<DOMWindow> m_source;
175     std::unique_ptr<MessagePortChannelArray> m_channels;
176     RefPtr<SecurityOrigin> m_targetOrigin;
177     RefPtr<ScriptCallStack> m_stackTrace;
178 };
179
180 typedef HashCountedSet<DOMWindow*> DOMWindowSet;
181
182 static DOMWindowSet& windowsWithUnloadEventListeners()
183 {
184     DEPRECATED_DEFINE_STATIC_LOCAL(DOMWindowSet, windowsWithUnloadEventListeners, ());
185     return windowsWithUnloadEventListeners;
186 }
187
188 static DOMWindowSet& windowsWithBeforeUnloadEventListeners()
189 {
190     DEPRECATED_DEFINE_STATIC_LOCAL(DOMWindowSet, windowsWithBeforeUnloadEventListeners, ());
191     return windowsWithBeforeUnloadEventListeners;
192 }
193
194 static void addUnloadEventListener(DOMWindow* domWindow)
195 {
196     if (windowsWithUnloadEventListeners().add(domWindow).isNewEntry)
197         domWindow->disableSuddenTermination();
198 }
199
200 static void removeUnloadEventListener(DOMWindow* domWindow)
201 {
202     if (windowsWithUnloadEventListeners().remove(domWindow))
203         domWindow->enableSuddenTermination();
204 }
205
206 static void removeAllUnloadEventListeners(DOMWindow* domWindow)
207 {
208     if (windowsWithUnloadEventListeners().removeAll(domWindow))
209         domWindow->enableSuddenTermination();
210 }
211
212 static void addBeforeUnloadEventListener(DOMWindow* domWindow)
213 {
214     if (windowsWithBeforeUnloadEventListeners().add(domWindow).isNewEntry)
215         domWindow->disableSuddenTermination();
216 }
217
218 static void removeBeforeUnloadEventListener(DOMWindow* domWindow)
219 {
220     if (windowsWithBeforeUnloadEventListeners().remove(domWindow))
221         domWindow->enableSuddenTermination();
222 }
223
224 static void removeAllBeforeUnloadEventListeners(DOMWindow* domWindow)
225 {
226     if (windowsWithBeforeUnloadEventListeners().removeAll(domWindow))
227         domWindow->enableSuddenTermination();
228 }
229
230 static bool allowsBeforeUnloadListeners(DOMWindow* window)
231 {
232     ASSERT_ARG(window, window);
233     Frame* frame = window->frame();
234     if (!frame)
235         return false;
236     if (!frame->page())
237         return false;
238     return frame->isMainFrame();
239 }
240
241 bool DOMWindow::dispatchAllPendingBeforeUnloadEvents()
242 {
243     DOMWindowSet& set = windowsWithBeforeUnloadEventListeners();
244     if (set.isEmpty())
245         return true;
246
247     static bool alreadyDispatched = false;
248     ASSERT(!alreadyDispatched);
249     if (alreadyDispatched)
250         return true;
251
252     Vector<Ref<DOMWindow>> windows;
253     windows.reserveInitialCapacity(set.size());
254     for (auto it = set.begin(), end = set.end(); it != end; ++it)
255         windows.uncheckedAppend(*it->key);
256
257     for (unsigned i = 0; i < windows.size(); ++i) {
258         DOMWindow& window = windows[i].get();
259         if (!set.contains(&window))
260             continue;
261
262         Frame* frame = window.frame();
263         if (!frame)
264             continue;
265
266         if (!frame->loader().shouldClose())
267             return false;
268
269         window.enableSuddenTermination();
270     }
271
272     alreadyDispatched = true;
273     return true;
274 }
275
276 unsigned DOMWindow::pendingUnloadEventListeners() const
277 {
278     return windowsWithUnloadEventListeners().count(const_cast<DOMWindow*>(this));
279 }
280
281 void DOMWindow::dispatchAllPendingUnloadEvents()
282 {
283     DOMWindowSet& set = windowsWithUnloadEventListeners();
284     if (set.isEmpty())
285         return;
286
287     static bool alreadyDispatched = false;
288     ASSERT(!alreadyDispatched);
289     if (alreadyDispatched)
290         return;
291
292     Vector<Ref<DOMWindow>> windows;
293     windows.reserveInitialCapacity(set.size());
294     for (auto it = set.begin(), end = set.end(); it != end; ++it)
295         windows.uncheckedAppend(*it->key);
296
297     for (unsigned i = 0; i < windows.size(); ++i) {
298         DOMWindow& window = windows[i].get();
299         if (!set.contains(&window))
300             continue;
301
302         window.dispatchEvent(PageTransitionEvent::create(eventNames().pagehideEvent, false), window.document());
303         window.dispatchEvent(Event::create(eventNames().unloadEvent, false, false), window.document());
304
305         window.enableSuddenTermination();
306     }
307
308     alreadyDispatched = true;
309 }
310
311 // This function:
312 // 1) Validates the pending changes are not changing any value to NaN; in that case keep original value.
313 // 2) Constrains the window rect to the minimum window size and no bigger than the float rect's dimensions.
314 // 3) Constrains the window rect to within the top and left boundaries of the available screen rect.
315 // 4) Constrains the window rect to within the bottom and right boundaries of the available screen rect.
316 // 5) Translate the window rect coordinates to be within the coordinate space of the screen.
317 FloatRect DOMWindow::adjustWindowRect(Page* page, const FloatRect& pendingChanges)
318 {
319     ASSERT(page);
320
321     FloatRect screen = screenAvailableRect(page->mainFrame().view());
322     FloatRect window = page->chrome().windowRect();
323
324     // Make sure we're in a valid state before adjusting dimensions.
325     ASSERT(std::isfinite(screen.x()));
326     ASSERT(std::isfinite(screen.y()));
327     ASSERT(std::isfinite(screen.width()));
328     ASSERT(std::isfinite(screen.height()));
329     ASSERT(std::isfinite(window.x()));
330     ASSERT(std::isfinite(window.y()));
331     ASSERT(std::isfinite(window.width()));
332     ASSERT(std::isfinite(window.height()));
333
334     // Update window values if new requested values are not NaN.
335     if (!std::isnan(pendingChanges.x()))
336         window.setX(pendingChanges.x());
337     if (!std::isnan(pendingChanges.y()))
338         window.setY(pendingChanges.y());
339     if (!std::isnan(pendingChanges.width()))
340         window.setWidth(pendingChanges.width());
341     if (!std::isnan(pendingChanges.height()))
342         window.setHeight(pendingChanges.height());
343
344     FloatSize minimumSize = page->chrome().client().minimumWindowSize();
345     window.setWidth(std::min(std::max(minimumSize.width(), window.width()), screen.width()));
346     window.setHeight(std::min(std::max(minimumSize.height(), window.height()), screen.height()));
347
348     // Constrain the window position within the valid screen area.
349     window.setX(std::max(screen.x(), std::min(window.x(), screen.maxX() - window.width())));
350     window.setY(std::max(screen.y(), std::min(window.y(), screen.maxY() - window.height())));
351
352     return window;
353 }
354
355 bool DOMWindow::allowPopUp(Frame* firstFrame)
356 {
357     ASSERT(firstFrame);
358
359     if (ScriptController::processingUserGesture())
360         return true;
361
362     return firstFrame->settings().javaScriptCanOpenWindowsAutomatically();
363 }
364
365 bool DOMWindow::allowPopUp()
366 {
367     return m_frame && allowPopUp(m_frame);
368 }
369
370 bool DOMWindow::canShowModalDialog(const Frame* frame)
371 {
372     if (!frame)
373         return false;
374     Page* page = frame->page();
375     if (!page)
376         return false;
377     return page->chrome().canRunModal();
378 }
379
380 bool DOMWindow::canShowModalDialogNow(const Frame* frame)
381 {
382     if (!frame)
383         return false;
384     Page* page = frame->page();
385     if (!page)
386         return false;
387     return page->chrome().canRunModalNow();
388 }
389
390 DOMWindow::DOMWindow(Document* document)
391     : ContextDestructionObserver(document)
392     , FrameDestructionObserver(document->frame())
393     , m_shouldPrintWhenFinishedLoading(false)
394     , m_suspendedForPageCache(false)
395     , m_lastPageStatus(PageStatusNone)
396     , m_weakPtrFactory(this)
397 #if PLATFORM(IOS)
398     , m_scrollEventListenerCount(0)
399 #endif
400 #if ENABLE(IOS_TOUCH_EVENTS) || ENABLE(IOS_GESTURE_EVENTS)
401     , m_touchEventListenerCount(0)
402 #endif
403 #if ENABLE(GAMEPAD)
404     , m_gamepadEventListenerCount(0)
405 #endif
406 {
407     ASSERT(frame());
408     ASSERT(DOMWindow::document());
409 }
410
411 void DOMWindow::didSecureTransitionTo(Document* document)
412 {
413     observeContext(document);
414 }
415
416 DOMWindow::~DOMWindow()
417 {
418 #ifndef NDEBUG
419     if (!m_suspendedForPageCache) {
420         ASSERT(!m_screen);
421         ASSERT(!m_history);
422         ASSERT(!m_crypto);
423         ASSERT(!m_locationbar);
424         ASSERT(!m_menubar);
425         ASSERT(!m_personalbar);
426         ASSERT(!m_scrollbars);
427         ASSERT(!m_statusbar);
428         ASSERT(!m_toolbar);
429         ASSERT(!m_navigator);
430 #if ENABLE(WEB_TIMING)
431         ASSERT(!m_performance);
432 #endif
433         ASSERT(!m_location);
434         ASSERT(!m_media);
435         ASSERT(!m_sessionStorage);
436         ASSERT(!m_localStorage);
437         ASSERT(!m_applicationCache);
438     }
439 #endif
440
441     if (m_suspendedForPageCache)
442         willDestroyCachedFrame();
443     else
444         willDestroyDocumentInFrame();
445
446     // As the ASSERTs above indicate, this reset should only be necessary if this DOMWindow is suspended for the page cache.
447     // But we don't want to risk any of these objects hanging around after we've been destroyed.
448     resetDOMWindowProperties();
449
450     removeAllUnloadEventListeners(this);
451     removeAllBeforeUnloadEventListeners(this);
452
453 #if ENABLE(GAMEPAD)
454     if (m_gamepadEventListenerCount)
455         GamepadManager::shared().unregisterDOMWindow(this);
456 #endif
457 }
458
459 DOMWindow* DOMWindow::toDOMWindow()
460 {
461     return this;
462 }
463
464 PassRefPtr<MediaQueryList> DOMWindow::matchMedia(const String& media)
465 {
466     return document() ? document()->mediaQueryMatcher().matchMedia(media) : 0;
467 }
468
469 Page* DOMWindow::page()
470 {
471     return frame() ? frame()->page() : 0;
472 }
473
474 void DOMWindow::frameDestroyed()
475 {
476     willDestroyDocumentInFrame();
477     FrameDestructionObserver::frameDestroyed();
478     resetDOMWindowProperties();
479     JSDOMWindowBase::fireFrameClearedWatchpointsForWindow(this);
480 }
481
482 void DOMWindow::willDetachPage()
483 {
484     InspectorInstrumentation::frameWindowDiscarded(m_frame, this);
485 }
486
487 void DOMWindow::willDestroyCachedFrame()
488 {
489     // It is necessary to copy m_properties to a separate vector because the DOMWindowProperties may
490     // unregister themselves from the DOMWindow as a result of the call to willDestroyGlobalObjectInCachedFrame.
491     Vector<DOMWindowProperty*> properties;
492     copyToVector(m_properties, properties);
493     for (size_t i = 0; i < properties.size(); ++i)
494         properties[i]->willDestroyGlobalObjectInCachedFrame();
495 }
496
497 void DOMWindow::willDestroyDocumentInFrame()
498 {
499     // It is necessary to copy m_properties to a separate vector because the DOMWindowProperties may
500     // unregister themselves from the DOMWindow as a result of the call to willDestroyGlobalObjectInFrame.
501     Vector<DOMWindowProperty*> properties;
502     copyToVector(m_properties, properties);
503     for (size_t i = 0; i < properties.size(); ++i)
504         properties[i]->willDestroyGlobalObjectInFrame();
505 }
506
507 void DOMWindow::willDetachDocumentFromFrame()
508 {
509     // It is necessary to copy m_properties to a separate vector because the DOMWindowProperties may
510     // unregister themselves from the DOMWindow as a result of the call to willDetachGlobalObjectFromFrame.
511     Vector<DOMWindowProperty*> properties;
512     copyToVector(m_properties, properties);
513     for (size_t i = 0; i < properties.size(); ++i)
514         properties[i]->willDetachGlobalObjectFromFrame();
515 }
516
517 #if ENABLE(GAMEPAD)
518 void DOMWindow::incrementGamepadEventListenerCount()
519 {
520     if (++m_gamepadEventListenerCount == 1)
521         GamepadManager::shared().registerDOMWindow(this);
522 }
523
524 void DOMWindow::decrementGamepadEventListenerCount()
525 {
526     ASSERT(m_gamepadEventListenerCount);
527
528     if (!--m_gamepadEventListenerCount)
529         GamepadManager::shared().unregisterDOMWindow(this);
530 }
531 #endif
532
533 void DOMWindow::registerProperty(DOMWindowProperty* property)
534 {
535     m_properties.add(property);
536 }
537
538 void DOMWindow::unregisterProperty(DOMWindowProperty* property)
539 {
540     m_properties.remove(property);
541 }
542
543 void DOMWindow::resetUnlessSuspendedForPageCache()
544 {
545     if (m_suspendedForPageCache)
546         return;
547     willDestroyDocumentInFrame();
548     resetDOMWindowProperties();
549 }
550
551 void DOMWindow::suspendForPageCache()
552 {
553     disconnectDOMWindowProperties();
554     m_suspendedForPageCache = true;
555 }
556
557 void DOMWindow::resumeFromPageCache()
558 {
559     reconnectDOMWindowProperties();
560     m_suspendedForPageCache = false;
561 }
562
563 void DOMWindow::disconnectDOMWindowProperties()
564 {
565     // It is necessary to copy m_properties to a separate vector because the DOMWindowProperties may
566     // unregister themselves from the DOMWindow as a result of the call to disconnectFrameForPageCache.
567     Vector<DOMWindowProperty*> properties;
568     copyToVector(m_properties, properties);
569     for (size_t i = 0; i < properties.size(); ++i)
570         properties[i]->disconnectFrameForPageCache();
571 }
572
573 void DOMWindow::reconnectDOMWindowProperties()
574 {
575     ASSERT(m_suspendedForPageCache);
576     // It is necessary to copy m_properties to a separate vector because the DOMWindowProperties may
577     // unregister themselves from the DOMWindow as a result of the call to reconnectFromPageCache.
578     Vector<DOMWindowProperty*> properties;
579     copyToVector(m_properties, properties);
580     for (size_t i = 0; i < properties.size(); ++i)
581         properties[i]->reconnectFrameFromPageCache(m_frame);
582 }
583
584 void DOMWindow::resetDOMWindowProperties()
585 {
586     m_properties.clear();
587
588     m_screen = 0;
589     m_history = 0;
590     m_crypto = 0;
591     m_locationbar = 0;
592     m_menubar = 0;
593     m_personalbar = 0;
594     m_scrollbars = 0;
595     m_statusbar = 0;
596     m_toolbar = 0;
597     m_navigator = 0;
598 #if ENABLE(WEB_TIMING)
599     m_performance = 0;
600 #endif
601     m_location = 0;
602     m_media = 0;
603     m_sessionStorage = 0;
604     m_localStorage = 0;
605     m_applicationCache = 0;
606 }
607
608 bool DOMWindow::isCurrentlyDisplayedInFrame() const
609 {
610     return m_frame && m_frame->document()->domWindow() == this;
611 }
612
613 #if ENABLE(ORIENTATION_EVENTS)
614 int DOMWindow::orientation() const
615 {
616     if (!m_frame)
617         return 0;
618
619     return m_frame->orientation();
620 }
621 #endif
622
623 Screen* DOMWindow::screen() const
624 {
625     if (!isCurrentlyDisplayedInFrame())
626         return 0;
627     if (!m_screen)
628         m_screen = Screen::create(m_frame);
629     return m_screen.get();
630 }
631
632 History* DOMWindow::history() const
633 {
634     if (!isCurrentlyDisplayedInFrame())
635         return 0;
636     if (!m_history)
637         m_history = History::create(m_frame);
638     return m_history.get();
639 }
640
641 Crypto* DOMWindow::crypto() const
642 {
643     // FIXME: Why is crypto not available when the window is not currently displayed in a frame?
644     if (!isCurrentlyDisplayedInFrame())
645         return 0;
646     if (!m_crypto)
647         m_crypto = Crypto::create(*document());
648     return m_crypto.get();
649 }
650
651 BarProp* DOMWindow::locationbar() const
652 {
653     if (!isCurrentlyDisplayedInFrame())
654         return 0;
655     if (!m_locationbar)
656         m_locationbar = BarProp::create(m_frame, BarProp::Locationbar);
657     return m_locationbar.get();
658 }
659
660 BarProp* DOMWindow::menubar() const
661 {
662     if (!isCurrentlyDisplayedInFrame())
663         return 0;
664     if (!m_menubar)
665         m_menubar = BarProp::create(m_frame, BarProp::Menubar);
666     return m_menubar.get();
667 }
668
669 BarProp* DOMWindow::personalbar() const
670 {
671     if (!isCurrentlyDisplayedInFrame())
672         return 0;
673     if (!m_personalbar)
674         m_personalbar = BarProp::create(m_frame, BarProp::Personalbar);
675     return m_personalbar.get();
676 }
677
678 BarProp* DOMWindow::scrollbars() const
679 {
680     if (!isCurrentlyDisplayedInFrame())
681         return 0;
682     if (!m_scrollbars)
683         m_scrollbars = BarProp::create(m_frame, BarProp::Scrollbars);
684     return m_scrollbars.get();
685 }
686
687 BarProp* DOMWindow::statusbar() const
688 {
689     if (!isCurrentlyDisplayedInFrame())
690         return 0;
691     if (!m_statusbar)
692         m_statusbar = BarProp::create(m_frame, BarProp::Statusbar);
693     return m_statusbar.get();
694 }
695
696 BarProp* DOMWindow::toolbar() const
697 {
698     if (!isCurrentlyDisplayedInFrame())
699         return 0;
700     if (!m_toolbar)
701         m_toolbar = BarProp::create(m_frame, BarProp::Toolbar);
702     return m_toolbar.get();
703 }
704
705 PageConsoleClient* DOMWindow::console() const
706 {
707     if (!isCurrentlyDisplayedInFrame())
708         return nullptr;
709     return m_frame->page() ? &m_frame->page()->console() : nullptr;
710 }
711
712 DOMApplicationCache* DOMWindow::applicationCache() const
713 {
714     if (!isCurrentlyDisplayedInFrame())
715         return 0;
716     if (!m_applicationCache)
717         m_applicationCache = DOMApplicationCache::create(m_frame);
718     return m_applicationCache.get();
719 }
720
721 Navigator* DOMWindow::navigator() const
722 {
723     if (!isCurrentlyDisplayedInFrame())
724         return 0;
725     if (!m_navigator)
726         m_navigator = Navigator::create(m_frame);
727     return m_navigator.get();
728 }
729
730 #if ENABLE(WEB_TIMING)
731 Performance* DOMWindow::performance() const
732 {
733     if (!isCurrentlyDisplayedInFrame())
734         return 0;
735     if (!m_performance)
736         m_performance = Performance::create(m_frame);
737     return m_performance.get();
738 }
739 #endif
740
741 Location* DOMWindow::location() const
742 {
743     if (!isCurrentlyDisplayedInFrame())
744         return 0;
745     if (!m_location)
746         m_location = Location::create(m_frame);
747     return m_location.get();
748 }
749
750 #if ENABLE(USER_MESSAGE_HANDLERS)
751 bool DOMWindow::shouldHaveWebKitNamespaceForWorld(DOMWrapperWorld& world)
752 {
753     if (!m_frame)
754         return false;
755
756     auto* page = m_frame->page();
757     if (!page)
758         return false;
759
760     auto* userContentController = page->userContentController();
761     if (!userContentController)
762         return false;
763
764     auto* descriptorMap = userContentController->userMessageHandlerDescriptors();
765     if (!descriptorMap)
766         return false;
767
768     for (auto& descriptor : descriptorMap->values()) {
769         if (&descriptor->world() == &world)
770             return true;
771     }
772
773     return false;
774 }
775
776 WebKitNamespace* DOMWindow::webkitNamespace() const
777 {
778     if (!isCurrentlyDisplayedInFrame())
779         return nullptr;
780     if (!m_webkitNamespace)
781         m_webkitNamespace = WebKitNamespace::create(*m_frame);
782     return m_webkitNamespace.get();
783 }
784 #endif
785
786 Storage* DOMWindow::sessionStorage(ExceptionCode& ec) const
787 {
788     if (!isCurrentlyDisplayedInFrame())
789         return 0;
790
791     Document* document = this->document();
792     if (!document)
793         return 0;
794
795     if (!document->securityOrigin()->canAccessSessionStorage(document->topOrigin())) {
796         ec = SECURITY_ERR;
797         return 0;
798     }
799
800     if (m_sessionStorage) {
801         if (!m_sessionStorage->area().canAccessStorage(m_frame)) {
802             ec = SECURITY_ERR;
803             return 0;
804         }
805         return m_sessionStorage.get();
806     }
807
808     Page* page = document->page();
809     if (!page)
810         return 0;
811
812     RefPtr<StorageArea> storageArea = page->sessionStorage()->storageArea(document->securityOrigin());
813     if (!storageArea->canAccessStorage(m_frame)) {
814         ec = SECURITY_ERR;
815         return 0;
816     }
817
818     m_sessionStorage = Storage::create(m_frame, storageArea.release());
819     return m_sessionStorage.get();
820 }
821
822 Storage* DOMWindow::localStorage(ExceptionCode& ec) const
823 {
824     if (!isCurrentlyDisplayedInFrame())
825         return nullptr;
826
827     Document* document = this->document();
828     if (!document)
829         return nullptr;
830
831     if (!document->securityOrigin()->canAccessLocalStorage(0)) {
832         ec = SECURITY_ERR;
833         return nullptr;
834     }
835
836     Page* page = document->page();
837     // FIXME: We should consider supporting access/modification to local storage
838     // after calling window.close(). See <https://bugs.webkit.org/show_bug.cgi?id=135330>.
839     if (!page || !page->isClosing()) {
840         if (m_localStorage) {
841             if (!m_localStorage->area().canAccessStorage(m_frame)) {
842                 ec = SECURITY_ERR;
843                 return nullptr;
844             }
845             return m_localStorage.get();
846         }
847     }
848
849     if (!page)
850         return nullptr;
851
852     if (page->isClosing())
853         return nullptr;
854
855     if (!page->settings().localStorageEnabled())
856         return nullptr;
857
858     RefPtr<StorageArea> storageArea;
859     if (!document->securityOrigin()->canAccessLocalStorage(document->topOrigin()))
860         storageArea = page->group().transientLocalStorage(document->topOrigin())->storageArea(document->securityOrigin());
861     else
862         storageArea = page->group().localStorage()->storageArea(document->securityOrigin());
863
864     if (!storageArea->canAccessStorage(m_frame)) {
865         ec = SECURITY_ERR;
866         return nullptr;
867     }
868
869     m_localStorage = Storage::create(m_frame, storageArea.release());
870     return m_localStorage.get();
871 }
872
873 void DOMWindow::postMessage(PassRefPtr<SerializedScriptValue> message, MessagePort* port, const String& targetOrigin, DOMWindow& source, ExceptionCode& ec)
874 {
875     MessagePortArray ports;
876     if (port)
877         ports.append(port);
878     postMessage(message, &ports, targetOrigin, source, ec);
879 }
880
881 void DOMWindow::postMessage(PassRefPtr<SerializedScriptValue> message, const MessagePortArray* ports, const String& targetOrigin, DOMWindow& source, ExceptionCode& ec)
882 {
883     if (!isCurrentlyDisplayedInFrame())
884         return;
885
886     Document* sourceDocument = source.document();
887
888     // Compute the target origin.  We need to do this synchronously in order
889     // to generate the SYNTAX_ERR exception correctly.
890     RefPtr<SecurityOrigin> target;
891     if (targetOrigin == "/") {
892         if (!sourceDocument)
893             return;
894         target = sourceDocument->securityOrigin();
895     } else if (targetOrigin != "*") {
896         target = SecurityOrigin::createFromString(targetOrigin);
897         // It doesn't make sense target a postMessage at a unique origin
898         // because there's no way to represent a unique origin in a string.
899         if (target->isUnique()) {
900             ec = SYNTAX_ERR;
901             return;
902         }
903     }
904
905     std::unique_ptr<MessagePortChannelArray> channels = MessagePort::disentanglePorts(ports, ec);
906     if (ec)
907         return;
908
909     // Capture the source of the message.  We need to do this synchronously
910     // in order to capture the source of the message correctly.
911     if (!sourceDocument)
912         return;
913     String sourceOrigin = sourceDocument->securityOrigin()->toString();
914
915     // Capture stack trace only when inspector front-end is loaded as it may be time consuming.
916     RefPtr<ScriptCallStack> stackTrace;
917     if (InspectorInstrumentation::consoleAgentEnabled(sourceDocument))
918         stackTrace = createScriptCallStack(JSMainThreadExecState::currentState(), ScriptCallStack::maxCallStackSizeToCapture);
919
920     // Schedule the message.
921     PostMessageTimer* timer = new PostMessageTimer(this, message, sourceOrigin, &source, WTF::move(channels), target.get(), stackTrace.release());
922     timer->startOneShot(0);
923 }
924
925 void DOMWindow::postMessageTimerFired(PostMessageTimer& timer)
926 {
927     if (!document() || !isCurrentlyDisplayedInFrame())
928         return;
929
930     dispatchMessageEventWithOriginCheck(timer.targetOrigin(), timer.event(document()), timer.stackTrace());
931 }
932
933 void DOMWindow::dispatchMessageEventWithOriginCheck(SecurityOrigin* intendedTargetOrigin, PassRefPtr<Event> event, PassRefPtr<ScriptCallStack> stackTrace)
934 {
935     if (intendedTargetOrigin) {
936         // Check target origin now since the target document may have changed since the timer was scheduled.
937         if (!intendedTargetOrigin->isSameSchemeHostPort(document()->securityOrigin())) {
938             String message = "Unable to post message to " + intendedTargetOrigin->toString() +
939                              ". Recipient has origin " + document()->securityOrigin()->toString() + ".\n";
940             console()->addMessage(MessageSource::Security, MessageLevel::Error, message, stackTrace);
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(0);
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 (unsigned i = 0; i < matchedRules.size(); ++i)
1456         ruleList->rules().append(matchedRules[i]->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, PassRefPtr<EventListener> listener, bool useCapture)
1696 {
1697     if (!EventTarget::addEventListener(eventType, listener, useCapture))
1698         return false;
1699
1700     if (Document* document = this->document()) {
1701         document->addListenerTypeIfNeeded(eventType);
1702         if (eventType == eventNames().wheelEvent || eventType == eventNames().mousewheelEvent)
1703             document->didAddWheelEventHandler();
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 (eventType == eventNames().wheelEvent || eventType == eventNames().mousewheelEvent)
1794             document->didRemoveWheelEventHandler();
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() : 0;
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->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)->toString() + "\" from accessing a frame at \"" + SecurityOrigin::create(targetURL)->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 PassRefPtr<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
2078     URL completedURL = urlString.isEmpty() ? URL(ParsedURLString, emptyString()) : firstFrame->document()->completeURL(urlString);
2079     if (!completedURL.isEmpty() && !completedURL.isValid()) {
2080         // Don't expose client code to invalid URLs.
2081         activeWindow.printErrorMessage("Unable to open a window with invalid URL '" + completedURL.string() + "'.\n");
2082         return 0;
2083     }
2084
2085     // For whatever reason, Firefox uses the first frame to determine the outgoingReferrer. We replicate that behavior here.
2086     String referrer = SecurityPolicy::generateReferrerHeader(firstFrame->document()->referrerPolicy(), completedURL, firstFrame->loader().outgoingReferrer());
2087
2088     ResourceRequest request(completedURL, referrer);
2089     FrameLoader::addHTTPOriginIfNeeded(request, firstFrame->loader().outgoingOrigin());
2090     FrameLoadRequest frameRequest(activeWindow.document()->securityOrigin(), request, frameName);
2091
2092     // We pass the opener frame for the lookupFrame in case the active frame is different from
2093     // the opener frame, and the name references a frame relative to the opener frame.
2094     bool created;
2095     RefPtr<Frame> newFrame = WebCore::createWindow(activeFrame, openerFrame, frameRequest, windowFeatures, created);
2096     if (!newFrame)
2097         return 0;
2098
2099     newFrame->loader().setOpener(openerFrame);
2100     newFrame->page()->setOpenedByDOM();
2101
2102     if (newFrame->document()->domWindow()->isInsecureScriptAccess(activeWindow, completedURL))
2103         return newFrame.release();
2104
2105     if (prepareDialogFunction)
2106         prepareDialogFunction(*newFrame->document()->domWindow());
2107
2108     if (created)
2109         newFrame->loader().changeLocation(activeWindow.document()->securityOrigin(), completedURL, referrer, LockHistory::No, LockBackForwardList::No);
2110     else if (!urlString.isEmpty()) {
2111         LockHistory lockHistory = ScriptController::processingUserGesture() ? LockHistory::No : LockHistory::Yes;
2112         newFrame->navigationScheduler().scheduleLocationChange(activeWindow.document()->securityOrigin(), completedURL, referrer, lockHistory, LockBackForwardList::No);
2113     }
2114
2115     // Navigating the new frame could result in it being detached from its page by a navigation policy delegate.
2116     if (!newFrame->page())
2117         return 0;
2118
2119     return newFrame.release();
2120 }
2121
2122 PassRefPtr<DOMWindow> DOMWindow::open(const String& urlString, const AtomicString& frameName, const String& windowFeaturesString,
2123     DOMWindow& activeWindow, DOMWindow& firstWindow)
2124 {
2125     if (!isCurrentlyDisplayedInFrame())
2126         return 0;
2127     Document* activeDocument = activeWindow.document();
2128     if (!activeDocument)
2129         return 0;
2130     Frame* firstFrame = firstWindow.frame();
2131     if (!firstFrame)
2132         return 0;
2133
2134     if (!firstWindow.allowPopUp()) {
2135         // Because FrameTree::find() returns true for empty strings, we must check for empty frame names.
2136         // Otherwise, illegitimate window.open() calls with no name will pass right through the popup blocker.
2137         if (frameName.isEmpty() || !m_frame->tree().find(frameName))
2138             return 0;
2139     }
2140
2141     // Get the target frame for the special cases of _top and _parent.
2142     // In those cases, we schedule a location change right now and return early.
2143     Frame* targetFrame = 0;
2144     if (frameName == "_top")
2145         targetFrame = &m_frame->tree().top();
2146     else if (frameName == "_parent") {
2147         if (Frame* parent = m_frame->tree().parent())
2148             targetFrame = parent;
2149         else
2150             targetFrame = m_frame;
2151     }
2152     if (targetFrame) {
2153         if (!activeDocument->canNavigate(targetFrame))
2154             return 0;
2155
2156         URL completedURL = firstFrame->document()->completeURL(urlString);
2157
2158         if (targetFrame->document()->domWindow()->isInsecureScriptAccess(activeWindow, completedURL))
2159             return targetFrame->document()->domWindow();
2160
2161         if (urlString.isEmpty())
2162             return targetFrame->document()->domWindow();
2163
2164         // For whatever reason, Firefox uses the first window rather than the active window to
2165         // determine the outgoing referrer. We replicate that behavior here.
2166         LockHistory lockHistory = ScriptController::processingUserGesture() ? LockHistory::No : LockHistory::Yes;
2167         targetFrame->navigationScheduler().scheduleLocationChange(activeDocument->securityOrigin(), completedURL, firstFrame->loader().outgoingReferrer(),
2168             lockHistory, LockBackForwardList::No);
2169         return targetFrame->document()->domWindow();
2170     }
2171
2172     WindowFeatures windowFeatures(windowFeaturesString);
2173     RefPtr<Frame> result = createWindow(urlString, frameName, windowFeatures, activeWindow, firstFrame, m_frame);
2174     return result ? result->document()->domWindow() : 0;
2175 }
2176
2177 void DOMWindow::showModalDialog(const String& urlString, const String& dialogFeaturesString, DOMWindow& activeWindow, DOMWindow& firstWindow, std::function<void (DOMWindow&)> prepareDialogFunction)
2178 {
2179     if (!isCurrentlyDisplayedInFrame())
2180         return;
2181     Frame* activeFrame = activeWindow.frame();
2182     if (!activeFrame)
2183         return;
2184     Frame* firstFrame = firstWindow.frame();
2185     if (!firstFrame)
2186         return;
2187
2188     // Pages are not allowed to cause modal alerts during BeforeUnload dispatch.
2189     if (page() && page()->isAnyFrameHandlingBeforeUnloadEvent()) {
2190         printErrorMessage("Use of window.showModalDialog is not allowed during beforeunload event dispatch.");
2191         return;
2192     }
2193
2194     if (!canShowModalDialogNow(m_frame) || !firstWindow.allowPopUp())
2195         return;
2196
2197     WindowFeatures windowFeatures(dialogFeaturesString, screenAvailableRect(m_frame->view()));
2198     RefPtr<Frame> dialogFrame = createWindow(urlString, emptyAtom, windowFeatures, activeWindow, firstFrame, m_frame, WTF::move(prepareDialogFunction));
2199     if (!dialogFrame)
2200         return;
2201     dialogFrame->page()->chrome().runModal();
2202 }
2203
2204 void DOMWindow::enableSuddenTermination()
2205 {
2206     if (Page* page = this->page())
2207         page->chrome().enableSuddenTermination();
2208 }
2209
2210 void DOMWindow::disableSuddenTermination()
2211 {
2212     if (Page* page = this->page())
2213         page->chrome().disableSuddenTermination();
2214 }
2215
2216 } // namespace WebCore