• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006, 2007, 2008, 2010 Apple Inc. All rights reserved.
3  * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include "config.h"
28 #include "core/frame/LocalDOMWindow.h"
29 
30 #include "bindings/v8/ExceptionMessages.h"
31 #include "bindings/v8/ExceptionState.h"
32 #include "bindings/v8/ExceptionStatePlaceholder.h"
33 #include "bindings/v8/ScriptCallStackFactory.h"
34 #include "bindings/v8/ScriptController.h"
35 #include "bindings/v8/SerializedScriptValue.h"
36 #include "core/css/CSSComputedStyleDeclaration.h"
37 #include "core/css/CSSRuleList.h"
38 #include "core/css/DOMWindowCSS.h"
39 #include "core/css/MediaQueryList.h"
40 #include "core/css/MediaQueryMatcher.h"
41 #include "core/css/StyleMedia.h"
42 #include "core/css/resolver/StyleResolver.h"
43 #include "core/dom/ContextFeatures.h"
44 #include "core/dom/DOMImplementation.h"
45 #include "core/dom/Document.h"
46 #include "core/dom/Element.h"
47 #include "core/dom/ExceptionCode.h"
48 #include "core/dom/ExecutionContext.h"
49 #include "core/dom/NoEventDispatchAssertion.h"
50 #include "core/dom/RequestAnimationFrameCallback.h"
51 #include "core/editing/Editor.h"
52 #include "core/events/DOMWindowEventQueue.h"
53 #include "core/events/EventListener.h"
54 #include "core/events/HashChangeEvent.h"
55 #include "core/events/MessageEvent.h"
56 #include "core/events/PageTransitionEvent.h"
57 #include "core/events/PopStateEvent.h"
58 #include "core/frame/BarProp.h"
59 #include "core/frame/Console.h"
60 #include "core/frame/DOMPoint.h"
61 #include "core/frame/DOMWindowLifecycleNotifier.h"
62 #include "core/frame/EventHandlerRegistry.h"
63 #include "core/frame/FrameConsole.h"
64 #include "core/frame/FrameHost.h"
65 #include "core/frame/FrameView.h"
66 #include "core/frame/History.h"
67 #include "core/frame/LocalFrame.h"
68 #include "core/frame/Location.h"
69 #include "core/frame/Navigator.h"
70 #include "core/frame/Screen.h"
71 #include "core/frame/Settings.h"
72 #include "core/html/HTMLFrameOwnerElement.h"
73 #include "core/inspector/InspectorInstrumentation.h"
74 #include "core/inspector/InspectorTraceEvents.h"
75 #include "core/inspector/ScriptCallStack.h"
76 #include "core/loader/DocumentLoader.h"
77 #include "core/loader/FrameLoadRequest.h"
78 #include "core/loader/FrameLoader.h"
79 #include "core/loader/FrameLoaderClient.h"
80 #include "core/loader/MixedContentChecker.h"
81 #include "core/loader/SinkDocument.h"
82 #include "core/loader/appcache/ApplicationCache.h"
83 #include "core/page/BackForwardClient.h"
84 #include "core/page/Chrome.h"
85 #include "core/page/ChromeClient.h"
86 #include "core/page/CreateWindow.h"
87 #include "core/page/EventHandler.h"
88 #include "core/page/FrameTree.h"
89 #include "core/page/Page.h"
90 #include "core/page/WindowFeatures.h"
91 #include "core/page/WindowFocusAllowedIndicator.h"
92 #include "core/page/scrolling/ScrollingCoordinator.h"
93 #include "core/storage/Storage.h"
94 #include "core/storage/StorageArea.h"
95 #include "core/storage/StorageNamespace.h"
96 #include "core/timing/Performance.h"
97 #include "platform/PlatformScreen.h"
98 #include "platform/RuntimeEnabledFeatures.h"
99 #include "platform/UserGestureIndicator.h"
100 #include "platform/geometry/FloatRect.h"
101 #include "platform/graphics/media/MediaPlayer.h"
102 #include "platform/weborigin/KURL.h"
103 #include "platform/weborigin/SecurityOrigin.h"
104 #include "platform/weborigin/SecurityPolicy.h"
105 #include "public/platform/Platform.h"
106 #include "wtf/MainThread.h"
107 #include "wtf/MathExtras.h"
108 #include "wtf/text/WTFString.h"
109 #include <algorithm>
110 
111 using std::min;
112 using std::max;
113 
114 namespace WebCore {
115 
116 class PostMessageTimer FINAL : public SuspendableTimer {
117 public:
PostMessageTimer(LocalDOMWindow & window,PassRefPtr<SerializedScriptValue> message,const String & sourceOrigin,PassRefPtrWillBeRawPtr<LocalDOMWindow> source,PassOwnPtr<MessagePortChannelArray> channels,SecurityOrigin * targetOrigin,PassRefPtrWillBeRawPtr<ScriptCallStack> stackTrace,UserGestureToken * userGestureToken)118     PostMessageTimer(LocalDOMWindow& window, PassRefPtr<SerializedScriptValue> message, const String& sourceOrigin, PassRefPtrWillBeRawPtr<LocalDOMWindow> source, PassOwnPtr<MessagePortChannelArray> channels, SecurityOrigin* targetOrigin, PassRefPtrWillBeRawPtr<ScriptCallStack> stackTrace, UserGestureToken* userGestureToken)
119         : SuspendableTimer(window.document())
120         , m_window(&window)
121         , m_message(message)
122         , m_origin(sourceOrigin)
123         , m_source(source)
124         , m_channels(channels)
125         , m_targetOrigin(targetOrigin)
126         , m_stackTrace(stackTrace)
127         , m_userGestureToken(userGestureToken)
128     {
129     }
130 
event()131     PassRefPtrWillBeRawPtr<MessageEvent> event()
132     {
133         return MessageEvent::create(m_channels.release(), m_message, m_origin, String(), m_source.get());
134 
135     }
targetOrigin() const136     SecurityOrigin* targetOrigin() const { return m_targetOrigin.get(); }
stackTrace() const137     ScriptCallStack* stackTrace() const { return m_stackTrace.get(); }
userGestureToken() const138     UserGestureToken* userGestureToken() const { return m_userGestureToken.get(); }
139 
140 private:
fired()141     virtual void fired() OVERRIDE
142     {
143         m_window->postMessageTimerFired(this);
144         // This object is deleted now.
145     }
146 
147     // FIXME: Oilpan: This raw pointer is safe because the PostMessageTimer is
148     // owned by the LocalDOMWindow. Ideally PostMessageTimer should be moved to
149     // the heap and use Member<LocalDOMWindow>.
150     LocalDOMWindow* m_window;
151     RefPtr<SerializedScriptValue> m_message;
152     String m_origin;
153     RefPtrWillBePersistent<LocalDOMWindow> m_source;
154     OwnPtr<MessagePortChannelArray> m_channels;
155     RefPtr<SecurityOrigin> m_targetOrigin;
156     RefPtrWillBePersistent<ScriptCallStack> m_stackTrace;
157     RefPtr<UserGestureToken> m_userGestureToken;
158 };
159 
disableSuddenTermination()160 static void disableSuddenTermination()
161 {
162     blink::Platform::current()->suddenTerminationChanged(false);
163 }
164 
enableSuddenTermination()165 static void enableSuddenTermination()
166 {
167     blink::Platform::current()->suddenTerminationChanged(true);
168 }
169 
170 typedef HashCountedSet<LocalDOMWindow*> DOMWindowSet;
171 
windowsWithUnloadEventListeners()172 static DOMWindowSet& windowsWithUnloadEventListeners()
173 {
174     DEFINE_STATIC_LOCAL(DOMWindowSet, windowsWithUnloadEventListeners, ());
175     return windowsWithUnloadEventListeners;
176 }
177 
windowsWithBeforeUnloadEventListeners()178 static DOMWindowSet& windowsWithBeforeUnloadEventListeners()
179 {
180     DEFINE_STATIC_LOCAL(DOMWindowSet, windowsWithBeforeUnloadEventListeners, ());
181     return windowsWithBeforeUnloadEventListeners;
182 }
183 
addUnloadEventListener(LocalDOMWindow * domWindow)184 static void addUnloadEventListener(LocalDOMWindow* domWindow)
185 {
186     DOMWindowSet& set = windowsWithUnloadEventListeners();
187     if (set.isEmpty())
188         disableSuddenTermination();
189     set.add(domWindow);
190 }
191 
removeUnloadEventListener(LocalDOMWindow * domWindow)192 static void removeUnloadEventListener(LocalDOMWindow* domWindow)
193 {
194     DOMWindowSet& set = windowsWithUnloadEventListeners();
195     DOMWindowSet::iterator it = set.find(domWindow);
196     if (it == set.end())
197         return;
198     set.remove(it);
199     if (set.isEmpty())
200         enableSuddenTermination();
201 }
202 
removeAllUnloadEventListeners(LocalDOMWindow * domWindow)203 static void removeAllUnloadEventListeners(LocalDOMWindow* domWindow)
204 {
205     DOMWindowSet& set = windowsWithUnloadEventListeners();
206     DOMWindowSet::iterator it = set.find(domWindow);
207     if (it == set.end())
208         return;
209     set.removeAll(it);
210     if (set.isEmpty())
211         enableSuddenTermination();
212 }
213 
addBeforeUnloadEventListener(LocalDOMWindow * domWindow)214 static void addBeforeUnloadEventListener(LocalDOMWindow* domWindow)
215 {
216     DOMWindowSet& set = windowsWithBeforeUnloadEventListeners();
217     if (set.isEmpty())
218         disableSuddenTermination();
219     set.add(domWindow);
220 }
221 
removeBeforeUnloadEventListener(LocalDOMWindow * domWindow)222 static void removeBeforeUnloadEventListener(LocalDOMWindow* domWindow)
223 {
224     DOMWindowSet& set = windowsWithBeforeUnloadEventListeners();
225     DOMWindowSet::iterator it = set.find(domWindow);
226     if (it == set.end())
227         return;
228     set.remove(it);
229     if (set.isEmpty())
230         enableSuddenTermination();
231 }
232 
removeAllBeforeUnloadEventListeners(LocalDOMWindow * domWindow)233 static void removeAllBeforeUnloadEventListeners(LocalDOMWindow* domWindow)
234 {
235     DOMWindowSet& set = windowsWithBeforeUnloadEventListeners();
236     DOMWindowSet::iterator it = set.find(domWindow);
237     if (it == set.end())
238         return;
239     set.removeAll(it);
240     if (set.isEmpty())
241         enableSuddenTermination();
242 }
243 
allowsBeforeUnloadListeners(LocalDOMWindow * window)244 static bool allowsBeforeUnloadListeners(LocalDOMWindow* window)
245 {
246     ASSERT_ARG(window, window);
247     LocalFrame* frame = window->frame();
248     if (!frame)
249         return false;
250     return frame->isMainFrame();
251 }
252 
pendingUnloadEventListeners() const253 unsigned LocalDOMWindow::pendingUnloadEventListeners() const
254 {
255     return windowsWithUnloadEventListeners().count(const_cast<LocalDOMWindow*>(this));
256 }
257 
258 // This function:
259 // 1) Validates the pending changes are not changing any value to NaN; in that case keep original value.
260 // 2) Constrains the window rect to the minimum window size and no bigger than the float rect's dimensions.
261 // 3) Constrains the window rect to within the top and left boundaries of the available screen rect.
262 // 4) Constrains the window rect to within the bottom and right boundaries of the available screen rect.
263 // 5) Translate the window rect coordinates to be within the coordinate space of the screen.
adjustWindowRect(LocalFrame & frame,const FloatRect & pendingChanges)264 FloatRect LocalDOMWindow::adjustWindowRect(LocalFrame& frame, const FloatRect& pendingChanges)
265 {
266     FrameHost* host = frame.host();
267     ASSERT(host);
268 
269     FloatRect screen = screenAvailableRect(frame.view());
270     FloatRect window = host->chrome().windowRect();
271 
272     // Make sure we're in a valid state before adjusting dimensions.
273     ASSERT(std::isfinite(screen.x()));
274     ASSERT(std::isfinite(screen.y()));
275     ASSERT(std::isfinite(screen.width()));
276     ASSERT(std::isfinite(screen.height()));
277     ASSERT(std::isfinite(window.x()));
278     ASSERT(std::isfinite(window.y()));
279     ASSERT(std::isfinite(window.width()));
280     ASSERT(std::isfinite(window.height()));
281 
282     // Update window values if new requested values are not NaN.
283     if (!std::isnan(pendingChanges.x()))
284         window.setX(pendingChanges.x());
285     if (!std::isnan(pendingChanges.y()))
286         window.setY(pendingChanges.y());
287     if (!std::isnan(pendingChanges.width()))
288         window.setWidth(pendingChanges.width());
289     if (!std::isnan(pendingChanges.height()))
290         window.setHeight(pendingChanges.height());
291 
292     FloatSize minimumSize = host->chrome().client().minimumWindowSize();
293     // Let size 0 pass through, since that indicates default size, not minimum size.
294     if (window.width())
295         window.setWidth(min(max(minimumSize.width(), window.width()), screen.width()));
296     if (window.height())
297         window.setHeight(min(max(minimumSize.height(), window.height()), screen.height()));
298 
299     // Constrain the window position within the valid screen area.
300     window.setX(max(screen.x(), min(window.x(), screen.maxX() - window.width())));
301     window.setY(max(screen.y(), min(window.y(), screen.maxY() - window.height())));
302 
303     return window;
304 }
305 
allowPopUp(LocalFrame & firstFrame)306 bool LocalDOMWindow::allowPopUp(LocalFrame& firstFrame)
307 {
308     if (UserGestureIndicator::processingUserGesture())
309         return true;
310 
311     Settings* settings = firstFrame.settings();
312     return settings && settings->javaScriptCanOpenWindowsAutomatically();
313 }
314 
allowPopUp()315 bool LocalDOMWindow::allowPopUp()
316 {
317     return m_frame && allowPopUp(*m_frame);
318 }
319 
canShowModalDialogNow(const LocalFrame * frame)320 bool LocalDOMWindow::canShowModalDialogNow(const LocalFrame* frame)
321 {
322     if (!frame)
323         return false;
324     FrameHost* host = frame->host();
325     if (!host)
326         return false;
327     return host->chrome().canRunModalNow();
328 }
329 
LocalDOMWindow(LocalFrame & frame)330 LocalDOMWindow::LocalDOMWindow(LocalFrame& frame)
331     : FrameDestructionObserver(&frame)
332     , m_shouldPrintWhenFinishedLoading(false)
333 #if ASSERT_ENABLED
334     , m_hasBeenReset(false)
335 #endif
336 {
337     ScriptWrappable::init(this);
338 }
339 
clearDocument()340 void LocalDOMWindow::clearDocument()
341 {
342     if (!m_document)
343         return;
344 
345     if (m_document->isActive()) {
346         // FIXME: We don't call willRemove here. Why is that OK?
347         // This detach() call is also mostly redundant. Most of the calls to
348         // this function come via DocumentLoader::createWriterFor, which
349         // always detaches the previous Document first. Only XSLTProcessor
350         // depends on this detach() call, so it seems like there's some room
351         // for cleanup.
352         m_document->detach();
353     }
354 
355     // FIXME: This should be part of ActiveDOMObject shutdown
356     clearEventQueue();
357 
358     m_document->clearDOMWindow();
359     m_document = nullptr;
360 }
361 
clearEventQueue()362 void LocalDOMWindow::clearEventQueue()
363 {
364     if (!m_eventQueue)
365         return;
366     m_eventQueue->close();
367     m_eventQueue.clear();
368 }
369 
acceptLanguagesChanged()370 void LocalDOMWindow::acceptLanguagesChanged()
371 {
372     if (m_navigator)
373         m_navigator->setLanguagesChanged();
374 
375     dispatchEvent(Event::create(EventTypeNames::languagechange));
376 }
377 
createDocument(const String & mimeType,const DocumentInit & init,bool forceXHTML)378 PassRefPtrWillBeRawPtr<Document> LocalDOMWindow::createDocument(const String& mimeType, const DocumentInit& init, bool forceXHTML)
379 {
380     RefPtrWillBeRawPtr<Document> document = nullptr;
381     if (forceXHTML) {
382         // This is a hack for XSLTProcessor. See XSLTProcessor::createDocumentFromSource().
383         document = Document::create(init);
384     } else {
385         document = DOMImplementation::createDocument(mimeType, init, init.frame() ? init.frame()->inViewSourceMode() : false);
386         if (document->isPluginDocument() && document->isSandboxed(SandboxPlugins))
387             document = SinkDocument::create(init);
388     }
389 
390     return document.release();
391 }
392 
installNewDocument(const String & mimeType,const DocumentInit & init,bool forceXHTML)393 PassRefPtrWillBeRawPtr<Document> LocalDOMWindow::installNewDocument(const String& mimeType, const DocumentInit& init, bool forceXHTML)
394 {
395     ASSERT(init.frame() == m_frame);
396 
397     clearDocument();
398 
399     m_document = createDocument(mimeType, init, forceXHTML);
400     m_eventQueue = DOMWindowEventQueue::create(m_document.get());
401     m_document->attach();
402 
403     if (!m_frame) {
404         // FIXME: Oilpan: Remove .get() when m_document becomes Member<>.
405         return m_document.get();
406     }
407 
408     m_frame->script().updateDocument();
409     m_document->updateViewportDescription();
410 
411     if (m_frame->page() && m_frame->view()) {
412         if (ScrollingCoordinator* scrollingCoordinator = m_frame->page()->scrollingCoordinator()) {
413             scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_frame->view(), HorizontalScrollbar);
414             scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_frame->view(), VerticalScrollbar);
415             scrollingCoordinator->scrollableAreaScrollLayerDidChange(m_frame->view());
416         }
417     }
418 
419     m_frame->selection().updateSecureKeyboardEntryIfActive();
420 
421     if (m_frame->isMainFrame()) {
422         if (m_document->hasTouchEventHandlers())
423             m_frame->host()->chrome().client().needTouchEvents(true);
424     }
425 
426     // FIXME: Oilpan: Remove .get() when m_document becomes Member<>.
427     return m_document.get();
428 }
429 
eventQueue() const430 EventQueue* LocalDOMWindow::eventQueue() const
431 {
432     return m_eventQueue.get();
433 }
434 
enqueueWindowEvent(PassRefPtrWillBeRawPtr<Event> event)435 void LocalDOMWindow::enqueueWindowEvent(PassRefPtrWillBeRawPtr<Event> event)
436 {
437     if (!m_eventQueue)
438         return;
439     event->setTarget(this);
440     m_eventQueue->enqueueEvent(event);
441 }
442 
enqueueDocumentEvent(PassRefPtrWillBeRawPtr<Event> event)443 void LocalDOMWindow::enqueueDocumentEvent(PassRefPtrWillBeRawPtr<Event> event)
444 {
445     if (!m_eventQueue)
446         return;
447     event->setTarget(m_document.get());
448     m_eventQueue->enqueueEvent(event);
449 }
450 
dispatchWindowLoadEvent()451 void LocalDOMWindow::dispatchWindowLoadEvent()
452 {
453     ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
454     dispatchLoadEvent();
455 }
456 
documentWasClosed()457 void LocalDOMWindow::documentWasClosed()
458 {
459     dispatchWindowLoadEvent();
460     enqueuePageshowEvent(PageshowEventNotPersisted);
461     if (m_pendingStateObject)
462         enqueuePopstateEvent(m_pendingStateObject.release());
463 }
464 
enqueuePageshowEvent(PageshowEventPersistence persisted)465 void LocalDOMWindow::enqueuePageshowEvent(PageshowEventPersistence persisted)
466 {
467     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=36334 Pageshow event needs to fire asynchronously.
468     // As per spec pageshow must be triggered asynchronously.
469     // However to be compatible with other browsers blink fires pageshow synchronously.
470     dispatchEvent(PageTransitionEvent::create(EventTypeNames::pageshow, persisted), m_document.get());
471 }
472 
enqueueHashchangeEvent(const String & oldURL,const String & newURL)473 void LocalDOMWindow::enqueueHashchangeEvent(const String& oldURL, const String& newURL)
474 {
475     enqueueWindowEvent(HashChangeEvent::create(oldURL, newURL));
476 }
477 
enqueuePopstateEvent(PassRefPtr<SerializedScriptValue> stateObject)478 void LocalDOMWindow::enqueuePopstateEvent(PassRefPtr<SerializedScriptValue> stateObject)
479 {
480     if (!ContextFeatures::pushStateEnabled(document()))
481         return;
482 
483     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=36202 Popstate event needs to fire asynchronously
484     dispatchEvent(PopStateEvent::create(stateObject, &history()));
485 }
486 
statePopped(PassRefPtr<SerializedScriptValue> stateObject)487 void LocalDOMWindow::statePopped(PassRefPtr<SerializedScriptValue> stateObject)
488 {
489     if (!frame())
490         return;
491 
492     // Per step 11 of section 6.5.9 (history traversal) of the HTML5 spec, we
493     // defer firing of popstate until we're in the complete state.
494     if (document()->isLoadCompleted())
495         enqueuePopstateEvent(stateObject);
496     else
497         m_pendingStateObject = stateObject;
498 }
499 
~LocalDOMWindow()500 LocalDOMWindow::~LocalDOMWindow()
501 {
502     ASSERT(m_hasBeenReset);
503     reset();
504 
505 #if ENABLE(OILPAN)
506     // Oilpan: the frame host and document objects are
507     // also garbage collected; cannot notify these
508     // when removing event listeners.
509     removeAllEventListenersInternal(DoNotBroadcastListenerRemoval);
510 
511     // Cleared when detaching document.
512     ASSERT(!m_eventQueue);
513 #else
514     removeAllEventListenersInternal(DoBroadcastListenerRemoval);
515 
516     ASSERT(m_document->isStopped());
517     clearDocument();
518 #endif
519 }
520 
interfaceName() const521 const AtomicString& LocalDOMWindow::interfaceName() const
522 {
523     return EventTargetNames::LocalDOMWindow;
524 }
525 
executionContext() const526 ExecutionContext* LocalDOMWindow::executionContext() const
527 {
528     return m_document.get();
529 }
530 
toDOMWindow()531 LocalDOMWindow* LocalDOMWindow::toDOMWindow()
532 {
533     return this;
534 }
535 
matchMedia(const String & media)536 PassRefPtrWillBeRawPtr<MediaQueryList> LocalDOMWindow::matchMedia(const String& media)
537 {
538     return document() ? document()->mediaQueryMatcher().matchMedia(media) : nullptr;
539 }
540 
page()541 Page* LocalDOMWindow::page()
542 {
543     return frame() ? frame()->page() : 0;
544 }
545 
frameDestroyed()546 void LocalDOMWindow::frameDestroyed()
547 {
548     FrameDestructionObserver::frameDestroyed();
549     reset();
550 }
551 
willDetachFrameHost()552 void LocalDOMWindow::willDetachFrameHost()
553 {
554     m_frame->host()->eventHandlerRegistry().didRemoveAllEventHandlers(*this);
555     InspectorInstrumentation::frameWindowDiscarded(m_frame, this);
556 }
557 
willDestroyDocumentInFrame()558 void LocalDOMWindow::willDestroyDocumentInFrame()
559 {
560     // It is necessary to copy m_properties to a separate vector because the DOMWindowProperties may
561     // unregister themselves from the LocalDOMWindow as a result of the call to willDestroyGlobalObjectInFrame.
562     Vector<DOMWindowProperty*> properties;
563     copyToVector(m_properties, properties);
564     for (size_t i = 0; i < properties.size(); ++i)
565         properties[i]->willDestroyGlobalObjectInFrame();
566 }
567 
willDetachDocumentFromFrame()568 void LocalDOMWindow::willDetachDocumentFromFrame()
569 {
570     // It is necessary to copy m_properties to a separate vector because the DOMWindowProperties may
571     // unregister themselves from the LocalDOMWindow as a result of the call to willDetachGlobalObjectFromFrame.
572     Vector<DOMWindowProperty*> properties;
573     copyToVector(m_properties, properties);
574     for (size_t i = 0; i < properties.size(); ++i)
575         properties[i]->willDetachGlobalObjectFromFrame();
576 }
577 
registerProperty(DOMWindowProperty * property)578 void LocalDOMWindow::registerProperty(DOMWindowProperty* property)
579 {
580     m_properties.add(property);
581 }
582 
unregisterProperty(DOMWindowProperty * property)583 void LocalDOMWindow::unregisterProperty(DOMWindowProperty* property)
584 {
585     m_properties.remove(property);
586 }
587 
reset()588 void LocalDOMWindow::reset()
589 {
590     willDestroyDocumentInFrame();
591     resetDOMWindowProperties();
592 }
593 
resetDOMWindowProperties()594 void LocalDOMWindow::resetDOMWindowProperties()
595 {
596     m_properties.clear();
597 
598     m_screen = nullptr;
599     m_history = nullptr;
600     m_locationbar = nullptr;
601     m_menubar = nullptr;
602     m_personalbar = nullptr;
603     m_scrollbars = nullptr;
604     m_statusbar = nullptr;
605     m_toolbar = nullptr;
606     m_console = nullptr;
607     m_navigator = nullptr;
608     m_performance = nullptr;
609     m_location = nullptr;
610     m_media = nullptr;
611     m_sessionStorage = nullptr;
612     m_localStorage = nullptr;
613     m_applicationCache = nullptr;
614 #if ASSERT_ENABLED
615     m_hasBeenReset = true;
616 #endif
617 }
618 
isCurrentlyDisplayedInFrame() const619 bool LocalDOMWindow::isCurrentlyDisplayedInFrame() const
620 {
621     return m_frame && m_frame->domWindow() == this && m_frame->host();
622 }
623 
orientation() const624 int LocalDOMWindow::orientation() const
625 {
626     ASSERT(RuntimeEnabledFeatures::orientationEventEnabled());
627 
628     if (!m_frame)
629         return 0;
630 
631     int orientation = screenOrientationAngle(m_frame->view());
632     // For backward compatibility, we want to return a value in the range of
633     // [-90; 180] instead of [0; 360[ because window.orientation used to behave
634     // like that in WebKit (this is a WebKit proprietary API).
635     if (orientation == 270)
636         return -90;
637     return orientation;
638 }
639 
screen() const640 Screen& LocalDOMWindow::screen() const
641 {
642     if (!m_screen)
643         m_screen = Screen::create(m_frame);
644     return *m_screen;
645 }
646 
history() const647 History& LocalDOMWindow::history() const
648 {
649     if (!m_history)
650         m_history = History::create(m_frame);
651     return *m_history;
652 }
653 
locationbar() const654 BarProp& LocalDOMWindow::locationbar() const
655 {
656     if (!m_locationbar)
657         m_locationbar = BarProp::create(m_frame, BarProp::Locationbar);
658     return *m_locationbar;
659 }
660 
menubar() const661 BarProp& LocalDOMWindow::menubar() const
662 {
663     if (!m_menubar)
664         m_menubar = BarProp::create(m_frame, BarProp::Menubar);
665     return *m_menubar;
666 }
667 
personalbar() const668 BarProp& LocalDOMWindow::personalbar() const
669 {
670     if (!m_personalbar)
671         m_personalbar = BarProp::create(m_frame, BarProp::Personalbar);
672     return *m_personalbar;
673 }
674 
scrollbars() const675 BarProp& LocalDOMWindow::scrollbars() const
676 {
677     if (!m_scrollbars)
678         m_scrollbars = BarProp::create(m_frame, BarProp::Scrollbars);
679     return *m_scrollbars;
680 }
681 
statusbar() const682 BarProp& LocalDOMWindow::statusbar() const
683 {
684     if (!m_statusbar)
685         m_statusbar = BarProp::create(m_frame, BarProp::Statusbar);
686     return *m_statusbar;
687 }
688 
toolbar() const689 BarProp& LocalDOMWindow::toolbar() const
690 {
691     if (!m_toolbar)
692         m_toolbar = BarProp::create(m_frame, BarProp::Toolbar);
693     return *m_toolbar;
694 }
695 
console() const696 Console& LocalDOMWindow::console() const
697 {
698     if (!m_console)
699         m_console = Console::create(m_frame);
700     return *m_console;
701 }
702 
frameConsole() const703 FrameConsole* LocalDOMWindow::frameConsole() const
704 {
705     if (!isCurrentlyDisplayedInFrame())
706         return 0;
707     return &m_frame->console();
708 }
709 
applicationCache() const710 ApplicationCache* LocalDOMWindow::applicationCache() const
711 {
712     if (!isCurrentlyDisplayedInFrame())
713         return 0;
714     if (!m_applicationCache)
715         m_applicationCache = ApplicationCache::create(m_frame);
716     return m_applicationCache.get();
717 }
718 
navigator() const719 Navigator& LocalDOMWindow::navigator() const
720 {
721     if (!m_navigator)
722         m_navigator = Navigator::create(m_frame);
723     return *m_navigator;
724 }
725 
performance() const726 Performance& LocalDOMWindow::performance() const
727 {
728     if (!m_performance)
729         m_performance = Performance::create(m_frame);
730     return *m_performance;
731 }
732 
location() const733 Location& LocalDOMWindow::location() const
734 {
735     if (!m_location)
736         m_location = Location::create(m_frame);
737     return *m_location;
738 }
739 
sessionStorage(ExceptionState & exceptionState) const740 Storage* LocalDOMWindow::sessionStorage(ExceptionState& exceptionState) const
741 {
742     if (!isCurrentlyDisplayedInFrame())
743         return 0;
744 
745     Document* document = this->document();
746     if (!document)
747         return 0;
748 
749     String accessDeniedMessage = "Access is denied for this document.";
750     if (!document->securityOrigin()->canAccessLocalStorage()) {
751         if (document->isSandboxed(SandboxOrigin))
752             exceptionState.throwSecurityError("The document is sandboxed and lacks the 'allow-same-origin' flag.");
753         else if (document->url().protocolIs("data"))
754             exceptionState.throwSecurityError("Storage is disabled inside 'data:' URLs.");
755         else
756             exceptionState.throwSecurityError(accessDeniedMessage);
757         return 0;
758     }
759 
760     if (m_sessionStorage) {
761         if (!m_sessionStorage->area()->canAccessStorage(m_frame)) {
762             exceptionState.throwSecurityError(accessDeniedMessage);
763             return 0;
764         }
765         return m_sessionStorage.get();
766     }
767 
768     Page* page = document->page();
769     if (!page)
770         return 0;
771 
772     OwnPtrWillBeRawPtr<StorageArea> storageArea = page->sessionStorage()->storageArea(document->securityOrigin());
773     if (!storageArea->canAccessStorage(m_frame)) {
774         exceptionState.throwSecurityError(accessDeniedMessage);
775         return 0;
776     }
777 
778     m_sessionStorage = Storage::create(m_frame, storageArea.release());
779     return m_sessionStorage.get();
780 }
781 
localStorage(ExceptionState & exceptionState) const782 Storage* LocalDOMWindow::localStorage(ExceptionState& exceptionState) const
783 {
784     if (!isCurrentlyDisplayedInFrame())
785         return 0;
786 
787     Document* document = this->document();
788     if (!document)
789         return 0;
790 
791     String accessDeniedMessage = "Access is denied for this document.";
792     if (!document->securityOrigin()->canAccessLocalStorage()) {
793         if (document->isSandboxed(SandboxOrigin))
794             exceptionState.throwSecurityError("The document is sandboxed and lacks the 'allow-same-origin' flag.");
795         else if (document->url().protocolIs("data"))
796             exceptionState.throwSecurityError("Storage is disabled inside 'data:' URLs.");
797         else
798             exceptionState.throwSecurityError(accessDeniedMessage);
799         return 0;
800     }
801 
802     if (m_localStorage) {
803         if (!m_localStorage->area()->canAccessStorage(m_frame)) {
804             exceptionState.throwSecurityError(accessDeniedMessage);
805             return 0;
806         }
807         return m_localStorage.get();
808     }
809 
810     // FIXME: Seems this check should be much higher?
811     FrameHost* host = document->frameHost();
812     if (!host || !host->settings().localStorageEnabled())
813         return 0;
814 
815     OwnPtrWillBeRawPtr<StorageArea> storageArea = StorageNamespace::localStorageArea(document->securityOrigin());
816     if (!storageArea->canAccessStorage(m_frame)) {
817         exceptionState.throwSecurityError(accessDeniedMessage);
818         return 0;
819     }
820 
821     m_localStorage = Storage::create(m_frame, storageArea.release());
822     return m_localStorage.get();
823 }
824 
postMessage(PassRefPtr<SerializedScriptValue> message,const MessagePortArray * ports,const String & targetOrigin,LocalDOMWindow * source,ExceptionState & exceptionState)825 void LocalDOMWindow::postMessage(PassRefPtr<SerializedScriptValue> message, const MessagePortArray* ports, const String& targetOrigin, LocalDOMWindow* source, ExceptionState& exceptionState)
826 {
827     if (!isCurrentlyDisplayedInFrame())
828         return;
829 
830     Document* sourceDocument = source->document();
831 
832     // Compute the target origin.  We need to do this synchronously in order
833     // to generate the SyntaxError exception correctly.
834     RefPtr<SecurityOrigin> target;
835     if (targetOrigin == "/") {
836         if (!sourceDocument)
837             return;
838         target = sourceDocument->securityOrigin();
839     } else if (targetOrigin != "*") {
840         target = SecurityOrigin::createFromString(targetOrigin);
841         // It doesn't make sense target a postMessage at a unique origin
842         // because there's no way to represent a unique origin in a string.
843         if (target->isUnique()) {
844             exceptionState.throwDOMException(SyntaxError, "Invalid target origin '" + targetOrigin + "' in a call to 'postMessage'.");
845             return;
846         }
847     }
848 
849     OwnPtr<MessagePortChannelArray> channels = MessagePort::disentanglePorts(ports, exceptionState);
850     if (exceptionState.hadException())
851         return;
852 
853     // Capture the source of the message.  We need to do this synchronously
854     // in order to capture the source of the message correctly.
855     if (!sourceDocument)
856         return;
857     String sourceOrigin = sourceDocument->securityOrigin()->toString();
858 
859     if (MixedContentChecker::isMixedContent(sourceDocument->securityOrigin(), document()->url()))
860         UseCounter::count(document(), UseCounter::PostMessageFromSecureToInsecure);
861     else if (MixedContentChecker::isMixedContent(document()->securityOrigin(), sourceDocument->url()))
862         UseCounter::count(document(), UseCounter::PostMessageFromInsecureToSecure);
863 
864     // Capture stack trace only when inspector front-end is loaded as it may be time consuming.
865     RefPtrWillBeRawPtr<ScriptCallStack> stackTrace = nullptr;
866     if (InspectorInstrumentation::consoleAgentEnabled(sourceDocument))
867         stackTrace = createScriptCallStack(ScriptCallStack::maxCallStackSizeToCapture, true);
868 
869     // Schedule the message.
870     OwnPtr<PostMessageTimer> timer = adoptPtr(new PostMessageTimer(*this, message, sourceOrigin, source, channels.release(), target.get(), stackTrace.release(), UserGestureIndicator::currentToken()));
871     timer->startOneShot(0, FROM_HERE);
872     timer->suspendIfNeeded();
873     m_postMessageTimers.add(timer.release());
874 }
875 
postMessageTimerFired(PostMessageTimer * timer)876 void LocalDOMWindow::postMessageTimerFired(PostMessageTimer* timer)
877 {
878     if (!isCurrentlyDisplayedInFrame()) {
879         m_postMessageTimers.remove(timer);
880         return;
881     }
882 
883     RefPtrWillBeRawPtr<MessageEvent> event = timer->event();
884 
885     // Give the embedder a chance to intercept this postMessage because this
886     // LocalDOMWindow might be a proxy for another in browsers that support
887     // postMessage calls across WebKit instances.
888     if (m_frame->loader().client()->willCheckAndDispatchMessageEvent(timer->targetOrigin(), event.get())) {
889         m_postMessageTimers.remove(timer);
890         return;
891     }
892 
893     UserGestureIndicator gestureIndicator(timer->userGestureToken());
894 
895     event->entangleMessagePorts(document());
896     dispatchMessageEventWithOriginCheck(timer->targetOrigin(), event, timer->stackTrace());
897     m_postMessageTimers.remove(timer);
898 }
899 
dispatchMessageEventWithOriginCheck(SecurityOrigin * intendedTargetOrigin,PassRefPtrWillBeRawPtr<Event> event,PassRefPtrWillBeRawPtr<ScriptCallStack> stackTrace)900 void LocalDOMWindow::dispatchMessageEventWithOriginCheck(SecurityOrigin* intendedTargetOrigin, PassRefPtrWillBeRawPtr<Event> event, PassRefPtrWillBeRawPtr<ScriptCallStack> stackTrace)
901 {
902     if (intendedTargetOrigin) {
903         // Check target origin now since the target document may have changed since the timer was scheduled.
904         if (!intendedTargetOrigin->isSameSchemeHostPort(document()->securityOrigin())) {
905             String message = ExceptionMessages::failedToExecute("postMessage", "DOMWindow", "The target origin provided ('" + intendedTargetOrigin->toString() + "') does not match the recipient window's origin ('" + document()->securityOrigin()->toString() + "').");
906             frameConsole()->addMessage(SecurityMessageSource, ErrorMessageLevel, message, stackTrace);
907             return;
908         }
909     }
910 
911     dispatchEvent(event);
912 }
913 
getSelection()914 DOMSelection* LocalDOMWindow::getSelection()
915 {
916     if (!isCurrentlyDisplayedInFrame() || !m_frame)
917         return 0;
918 
919     return m_frame->document()->getSelection();
920 }
921 
frameElement() const922 Element* LocalDOMWindow::frameElement() const
923 {
924     if (!m_frame)
925         return 0;
926 
927     // The bindings security check should ensure we're same origin...
928     ASSERT(!m_frame->owner() || m_frame->owner()->isLocal());
929     return m_frame->deprecatedLocalOwner();
930 }
931 
focus(ExecutionContext * context)932 void LocalDOMWindow::focus(ExecutionContext* context)
933 {
934     if (!m_frame)
935         return;
936 
937     FrameHost* host = m_frame->host();
938     if (!host)
939         return;
940 
941     bool allowFocus = WindowFocusAllowedIndicator::windowFocusAllowed();
942     if (context) {
943         ASSERT(isMainThread());
944         Document* activeDocument = toDocument(context);
945         if (opener() && opener() != this && activeDocument->domWindow() == opener())
946             allowFocus = true;
947     }
948 
949     // If we're a top level window, bring the window to the front.
950     if (m_frame->isMainFrame() && allowFocus)
951         host->chrome().focus();
952 
953     if (!m_frame)
954         return;
955 
956     m_frame->eventHandler().focusDocumentView();
957 }
958 
blur()959 void LocalDOMWindow::blur()
960 {
961 }
962 
close(ExecutionContext * context)963 void LocalDOMWindow::close(ExecutionContext* context)
964 {
965     if (!m_frame || !m_frame->isMainFrame())
966         return;
967 
968     Page* page = m_frame->page();
969     if (!page)
970         return;
971 
972     if (context) {
973         ASSERT(isMainThread());
974         Document* activeDocument = toDocument(context);
975         if (!activeDocument)
976             return;
977 
978         if (!activeDocument->canNavigate(*m_frame))
979             return;
980     }
981 
982     Settings* settings = m_frame->settings();
983     bool allowScriptsToCloseWindows = settings && settings->allowScriptsToCloseWindows();
984 
985     if (!(page->openedByDOM() || page->backForward().backForwardListCount() <= 1 || allowScriptsToCloseWindows)) {
986         frameConsole()->addMessage(JSMessageSource, WarningMessageLevel, "Scripts may close only the windows that were opened by it.");
987         return;
988     }
989 
990     if (!m_frame->loader().shouldClose())
991         return;
992 
993     page->chrome().closeWindowSoon();
994 }
995 
print()996 void LocalDOMWindow::print()
997 {
998     if (!m_frame)
999         return;
1000 
1001     FrameHost* host = m_frame->host();
1002     if (!host)
1003         return;
1004 
1005     if (m_frame->loader().state() != FrameStateComplete) {
1006         m_shouldPrintWhenFinishedLoading = true;
1007         return;
1008     }
1009     m_shouldPrintWhenFinishedLoading = false;
1010     host->chrome().print(m_frame);
1011 }
1012 
stop()1013 void LocalDOMWindow::stop()
1014 {
1015     if (!m_frame)
1016         return;
1017     m_frame->loader().stopAllLoaders();
1018 }
1019 
alert(const String & message)1020 void LocalDOMWindow::alert(const String& message)
1021 {
1022     if (!m_frame)
1023         return;
1024 
1025     m_frame->document()->updateRenderTreeIfNeeded();
1026 
1027     FrameHost* host = m_frame->host();
1028     if (!host)
1029         return;
1030 
1031     host->chrome().runJavaScriptAlert(m_frame, message);
1032 }
1033 
confirm(const String & message)1034 bool LocalDOMWindow::confirm(const String& message)
1035 {
1036     if (!m_frame)
1037         return false;
1038 
1039     m_frame->document()->updateRenderTreeIfNeeded();
1040 
1041     FrameHost* host = m_frame->host();
1042     if (!host)
1043         return false;
1044 
1045     return host->chrome().runJavaScriptConfirm(m_frame, message);
1046 }
1047 
prompt(const String & message,const String & defaultValue)1048 String LocalDOMWindow::prompt(const String& message, const String& defaultValue)
1049 {
1050     if (!m_frame)
1051         return String();
1052 
1053     m_frame->document()->updateRenderTreeIfNeeded();
1054 
1055     FrameHost* host = m_frame->host();
1056     if (!host)
1057         return String();
1058 
1059     String returnValue;
1060     if (host->chrome().runJavaScriptPrompt(m_frame, message, defaultValue, returnValue))
1061         return returnValue;
1062 
1063     return String();
1064 }
1065 
find(const String & string,bool caseSensitive,bool backwards,bool wrap,bool,bool,bool) const1066 bool LocalDOMWindow::find(const String& string, bool caseSensitive, bool backwards, bool wrap, bool /*wholeWord*/, bool /*searchInFrames*/, bool /*showDialog*/) const
1067 {
1068     if (!isCurrentlyDisplayedInFrame())
1069         return false;
1070 
1071     // |m_frame| can be destructed during |Editor::findString()| via
1072     // |Document::updateLayou()|, e.g. event handler removes a frame.
1073     RefPtr<LocalFrame> protectFrame(m_frame);
1074 
1075     // FIXME (13016): Support wholeWord, searchInFrames and showDialog
1076     return m_frame->editor().findString(string, !backwards, caseSensitive, wrap, false);
1077 }
1078 
offscreenBuffering() const1079 bool LocalDOMWindow::offscreenBuffering() const
1080 {
1081     return true;
1082 }
1083 
outerHeight() const1084 int LocalDOMWindow::outerHeight() const
1085 {
1086     if (!m_frame)
1087         return 0;
1088 
1089     FrameHost* host = m_frame->host();
1090     if (!host)
1091         return 0;
1092 
1093     if (host->settings().reportScreenSizeInPhysicalPixelsQuirk())
1094         return lroundf(host->chrome().windowRect().height() * host->deviceScaleFactor());
1095     return static_cast<int>(host->chrome().windowRect().height());
1096 }
1097 
outerWidth() const1098 int LocalDOMWindow::outerWidth() const
1099 {
1100     if (!m_frame)
1101         return 0;
1102 
1103     FrameHost* host = m_frame->host();
1104     if (!host)
1105         return 0;
1106 
1107     if (host->settings().reportScreenSizeInPhysicalPixelsQuirk())
1108         return lroundf(host->chrome().windowRect().width() * host->deviceScaleFactor());
1109     return static_cast<int>(host->chrome().windowRect().width());
1110 }
1111 
innerHeight() const1112 int LocalDOMWindow::innerHeight() const
1113 {
1114     if (!m_frame)
1115         return 0;
1116 
1117     FrameView* view = m_frame->view();
1118     if (!view)
1119         return 0;
1120 
1121     // FIXME: This is potentially too much work. We really only need to know the dimensions of the parent frame's renderer.
1122     if (Frame* parent = m_frame->tree().parent()) {
1123         if (parent && parent->isLocalFrame())
1124             toLocalFrame(parent)->document()->updateLayoutIgnorePendingStylesheets();
1125     }
1126 
1127     return adjustForAbsoluteZoom(view->visibleContentRect(IncludeScrollbars).height(), m_frame->pageZoomFactor());
1128 }
1129 
innerWidth() const1130 int LocalDOMWindow::innerWidth() const
1131 {
1132     if (!m_frame)
1133         return 0;
1134 
1135     FrameView* view = m_frame->view();
1136     if (!view)
1137         return 0;
1138 
1139     // FIXME: This is potentially too much work. We really only need to know the dimensions of the parent frame's renderer.
1140     if (Frame* parent = m_frame->tree().parent()) {
1141         if (parent && parent->isLocalFrame())
1142             toLocalFrame(parent)->document()->updateLayoutIgnorePendingStylesheets();
1143     }
1144 
1145     return adjustForAbsoluteZoom(view->visibleContentRect(IncludeScrollbars).width(), m_frame->pageZoomFactor());
1146 }
1147 
screenX() const1148 int LocalDOMWindow::screenX() const
1149 {
1150     if (!m_frame)
1151         return 0;
1152 
1153     FrameHost* host = m_frame->host();
1154     if (!host)
1155         return 0;
1156 
1157     if (host->settings().reportScreenSizeInPhysicalPixelsQuirk())
1158         return lroundf(host->chrome().windowRect().x() * host->deviceScaleFactor());
1159     return static_cast<int>(host->chrome().windowRect().x());
1160 }
1161 
screenY() const1162 int LocalDOMWindow::screenY() const
1163 {
1164     if (!m_frame)
1165         return 0;
1166 
1167     FrameHost* host = m_frame->host();
1168     if (!host)
1169         return 0;
1170 
1171     if (host->settings().reportScreenSizeInPhysicalPixelsQuirk())
1172         return lroundf(host->chrome().windowRect().y() * host->deviceScaleFactor());
1173     return static_cast<int>(host->chrome().windowRect().y());
1174 }
1175 
scrollX() const1176 int LocalDOMWindow::scrollX() const
1177 {
1178     if (!m_frame)
1179         return 0;
1180 
1181     FrameView* view = m_frame->view();
1182     if (!view)
1183         return 0;
1184 
1185     m_frame->document()->updateLayoutIgnorePendingStylesheets();
1186 
1187     return adjustForAbsoluteZoom(view->scrollX(), m_frame->pageZoomFactor());
1188 }
1189 
scrollY() const1190 int LocalDOMWindow::scrollY() const
1191 {
1192     if (!m_frame)
1193         return 0;
1194 
1195     FrameView* view = m_frame->view();
1196     if (!view)
1197         return 0;
1198 
1199     m_frame->document()->updateLayoutIgnorePendingStylesheets();
1200 
1201     return adjustForAbsoluteZoom(view->scrollY(), m_frame->pageZoomFactor());
1202 }
1203 
closed() const1204 bool LocalDOMWindow::closed() const
1205 {
1206     return !m_frame;
1207 }
1208 
length() const1209 unsigned LocalDOMWindow::length() const
1210 {
1211     if (!isCurrentlyDisplayedInFrame())
1212         return 0;
1213 
1214     return m_frame->tree().scopedChildCount();
1215 }
1216 
name() const1217 const AtomicString& LocalDOMWindow::name() const
1218 {
1219     if (!isCurrentlyDisplayedInFrame())
1220         return nullAtom;
1221 
1222     return m_frame->tree().name();
1223 }
1224 
setName(const AtomicString & name)1225 void LocalDOMWindow::setName(const AtomicString& name)
1226 {
1227     if (!isCurrentlyDisplayedInFrame())
1228         return;
1229 
1230     m_frame->tree().setName(name);
1231     ASSERT(m_frame->loader().client());
1232     m_frame->loader().client()->didChangeName(name);
1233 }
1234 
setStatus(const String & string)1235 void LocalDOMWindow::setStatus(const String& string)
1236 {
1237     m_status = string;
1238 
1239     if (!m_frame)
1240         return;
1241 
1242     FrameHost* host = m_frame->host();
1243     if (!host)
1244         return;
1245 
1246     ASSERT(m_frame->document()); // Client calls shouldn't be made when the frame is in inconsistent state.
1247     host->chrome().setStatusbarText(m_frame, m_status);
1248 }
1249 
setDefaultStatus(const String & string)1250 void LocalDOMWindow::setDefaultStatus(const String& string)
1251 {
1252     m_defaultStatus = string;
1253 
1254     if (!m_frame)
1255         return;
1256 
1257     FrameHost* host = m_frame->host();
1258     if (!host)
1259         return;
1260 
1261     ASSERT(m_frame->document()); // Client calls shouldn't be made when the frame is in inconsistent state.
1262     host->chrome().setStatusbarText(m_frame, m_defaultStatus);
1263 }
1264 
self() const1265 LocalDOMWindow* LocalDOMWindow::self() const
1266 {
1267     if (!m_frame)
1268         return 0;
1269 
1270     return m_frame->domWindow();
1271 }
1272 
opener() const1273 LocalDOMWindow* LocalDOMWindow::opener() const
1274 {
1275     if (!m_frame)
1276         return 0;
1277 
1278     LocalFrame* opener = m_frame->loader().opener();
1279     if (!opener)
1280         return 0;
1281 
1282     return opener->domWindow();
1283 }
1284 
parent() const1285 LocalDOMWindow* LocalDOMWindow::parent() const
1286 {
1287     if (!m_frame)
1288         return 0;
1289 
1290     Frame* parent = m_frame->tree().parent();
1291     if (parent)
1292         return parent->domWindow();
1293 
1294     return m_frame->domWindow();
1295 }
1296 
top() const1297 LocalDOMWindow* LocalDOMWindow::top() const
1298 {
1299     if (!m_frame)
1300         return 0;
1301 
1302     return m_frame->tree().top()->domWindow();
1303 }
1304 
document() const1305 Document* LocalDOMWindow::document() const
1306 {
1307     return m_document.get();
1308 }
1309 
styleMedia() const1310 StyleMedia& LocalDOMWindow::styleMedia() const
1311 {
1312     if (!m_media)
1313         m_media = StyleMedia::create(m_frame);
1314     return *m_media;
1315 }
1316 
getComputedStyle(Element * elt,const String & pseudoElt) const1317 PassRefPtrWillBeRawPtr<CSSStyleDeclaration> LocalDOMWindow::getComputedStyle(Element* elt, const String& pseudoElt) const
1318 {
1319     if (!elt)
1320         return nullptr;
1321 
1322     return CSSComputedStyleDeclaration::create(elt, false, pseudoElt);
1323 }
1324 
getMatchedCSSRules(Element * element,const String & pseudoElement) const1325 PassRefPtrWillBeRawPtr<CSSRuleList> LocalDOMWindow::getMatchedCSSRules(Element* element, const String& pseudoElement) const
1326 {
1327     if (!element)
1328         return nullptr;
1329 
1330     if (!isCurrentlyDisplayedInFrame())
1331         return nullptr;
1332 
1333     unsigned colonStart = pseudoElement[0] == ':' ? (pseudoElement[1] == ':' ? 2 : 1) : 0;
1334     CSSSelector::PseudoType pseudoType = CSSSelector::parsePseudoType(AtomicString(pseudoElement.substring(colonStart)));
1335     if (pseudoType == CSSSelector::PseudoUnknown && !pseudoElement.isEmpty())
1336         return nullptr;
1337 
1338     unsigned rulesToInclude = StyleResolver::AuthorCSSRules;
1339     PseudoId pseudoId = CSSSelector::pseudoId(pseudoType);
1340     return m_frame->document()->ensureStyleResolver().pseudoCSSRulesForElement(element, pseudoId, rulesToInclude);
1341 }
1342 
webkitConvertPointFromNodeToPage(Node * node,const DOMPoint * p) const1343 PassRefPtrWillBeRawPtr<DOMPoint> LocalDOMWindow::webkitConvertPointFromNodeToPage(Node* node, const DOMPoint* p) const
1344 {
1345     if (!node || !p)
1346         return nullptr;
1347 
1348     if (!document())
1349         return nullptr;
1350 
1351     document()->updateLayoutIgnorePendingStylesheets();
1352 
1353     FloatPoint pagePoint(p->x(), p->y());
1354     pagePoint = node->convertToPage(pagePoint);
1355     return DOMPoint::create(pagePoint.x(), pagePoint.y());
1356 }
1357 
webkitConvertPointFromPageToNode(Node * node,const DOMPoint * p) const1358 PassRefPtrWillBeRawPtr<DOMPoint> LocalDOMWindow::webkitConvertPointFromPageToNode(Node* node, const DOMPoint* p) const
1359 {
1360     if (!node || !p)
1361         return nullptr;
1362 
1363     if (!document())
1364         return nullptr;
1365 
1366     document()->updateLayoutIgnorePendingStylesheets();
1367 
1368     FloatPoint nodePoint(p->x(), p->y());
1369     nodePoint = node->convertFromPage(nodePoint);
1370     return DOMPoint::create(nodePoint.x(), nodePoint.y());
1371 }
1372 
devicePixelRatio() const1373 double LocalDOMWindow::devicePixelRatio() const
1374 {
1375     if (!m_frame)
1376         return 0.0;
1377 
1378     return m_frame->devicePixelRatio();
1379 }
1380 
scrollBehaviorFromScrollOptions(const Dictionary & scrollOptions,ScrollBehavior & scrollBehavior,ExceptionState & exceptionState)1381 static bool scrollBehaviorFromScrollOptions(const Dictionary& scrollOptions, ScrollBehavior& scrollBehavior, ExceptionState& exceptionState)
1382 {
1383     String scrollBehaviorString;
1384     if (!scrollOptions.get("behavior", scrollBehaviorString)) {
1385         scrollBehavior = ScrollBehaviorAuto;
1386         return true;
1387     }
1388 
1389     if (ScrollableArea::scrollBehaviorFromString(scrollBehaviorString, scrollBehavior))
1390         return true;
1391 
1392     exceptionState.throwTypeError("The ScrollBehavior provided is invalid.");
1393     return false;
1394 }
1395 
scrollBy(int x,int y) const1396 void LocalDOMWindow::scrollBy(int x, int y) const
1397 {
1398     if (!isCurrentlyDisplayedInFrame())
1399         return;
1400 
1401     document()->updateLayoutIgnorePendingStylesheets();
1402 
1403     FrameView* view = m_frame->view();
1404     if (!view)
1405         return;
1406 
1407     IntSize scaledOffset(x * m_frame->pageZoomFactor(), y * m_frame->pageZoomFactor());
1408     // FIXME: Use scrollBehavior to decide whether to scroll smoothly or instantly.
1409     view->scrollBy(scaledOffset);
1410 }
1411 
scrollBy(int x,int y,const Dictionary & scrollOptions,ExceptionState & exceptionState) const1412 void LocalDOMWindow::scrollBy(int x, int y, const Dictionary& scrollOptions, ExceptionState &exceptionState) const
1413 {
1414     ScrollBehavior scrollBehavior = ScrollBehaviorAuto;
1415     if (!scrollBehaviorFromScrollOptions(scrollOptions, scrollBehavior, exceptionState))
1416         return;
1417     scrollBy(x, y);
1418 }
1419 
scrollTo(int x,int y) const1420 void LocalDOMWindow::scrollTo(int x, int y) const
1421 {
1422     if (!isCurrentlyDisplayedInFrame())
1423         return;
1424 
1425     document()->updateLayoutIgnorePendingStylesheets();
1426 
1427     RefPtr<FrameView> view = m_frame->view();
1428     if (!view)
1429         return;
1430 
1431     IntPoint layoutPos(x * m_frame->pageZoomFactor(), y * m_frame->pageZoomFactor());
1432     // FIXME: Use scrollBehavior to decide whether to scroll smoothly or instantly.
1433     view->setScrollPosition(layoutPos);
1434 }
1435 
scrollTo(int x,int y,const Dictionary & scrollOptions,ExceptionState & exceptionState) const1436 void LocalDOMWindow::scrollTo(int x, int y, const Dictionary& scrollOptions, ExceptionState& exceptionState) const
1437 {
1438     ScrollBehavior scrollBehavior = ScrollBehaviorAuto;
1439     if (!scrollBehaviorFromScrollOptions(scrollOptions, scrollBehavior, exceptionState))
1440         return;
1441     scrollTo(x, y);
1442 }
1443 
moveBy(float x,float y) const1444 void LocalDOMWindow::moveBy(float x, float y) const
1445 {
1446     if (!m_frame || !m_frame->isMainFrame())
1447         return;
1448 
1449     FrameHost* host = m_frame->host();
1450     if (!host)
1451         return;
1452 
1453     FloatRect windowRect = host->chrome().windowRect();
1454     windowRect.move(x, y);
1455     // Security check (the spec talks about UniversalBrowserWrite to disable this check...)
1456     host->chrome().setWindowRect(adjustWindowRect(*m_frame, windowRect));
1457 }
1458 
moveTo(float x,float y) const1459 void LocalDOMWindow::moveTo(float x, float y) const
1460 {
1461     if (!m_frame || !m_frame->isMainFrame())
1462         return;
1463 
1464     FrameHost* host = m_frame->host();
1465     if (!host)
1466         return;
1467 
1468     FloatRect windowRect = host->chrome().windowRect();
1469     windowRect.setLocation(FloatPoint(x, y));
1470     // Security check (the spec talks about UniversalBrowserWrite to disable this check...)
1471     host->chrome().setWindowRect(adjustWindowRect(*m_frame, windowRect));
1472 }
1473 
resizeBy(float x,float y) const1474 void LocalDOMWindow::resizeBy(float x, float y) const
1475 {
1476     if (!m_frame || !m_frame->isMainFrame())
1477         return;
1478 
1479     FrameHost* host = m_frame->host();
1480     if (!host)
1481         return;
1482 
1483     FloatRect fr = host->chrome().windowRect();
1484     FloatSize dest = fr.size() + FloatSize(x, y);
1485     FloatRect update(fr.location(), dest);
1486     host->chrome().setWindowRect(adjustWindowRect(*m_frame, update));
1487 }
1488 
resizeTo(float width,float height) const1489 void LocalDOMWindow::resizeTo(float width, float height) const
1490 {
1491     if (!m_frame || !m_frame->isMainFrame())
1492         return;
1493 
1494     FrameHost* host = m_frame->host();
1495     if (!host)
1496         return;
1497 
1498     FloatRect fr = host->chrome().windowRect();
1499     FloatSize dest = FloatSize(width, height);
1500     FloatRect update(fr.location(), dest);
1501     host->chrome().setWindowRect(adjustWindowRect(*m_frame, update));
1502 }
1503 
requestAnimationFrame(PassOwnPtr<RequestAnimationFrameCallback> callback)1504 int LocalDOMWindow::requestAnimationFrame(PassOwnPtr<RequestAnimationFrameCallback> callback)
1505 {
1506     callback->m_useLegacyTimeBase = false;
1507     if (Document* d = document())
1508         return d->requestAnimationFrame(callback);
1509     return 0;
1510 }
1511 
webkitRequestAnimationFrame(PassOwnPtr<RequestAnimationFrameCallback> callback)1512 int LocalDOMWindow::webkitRequestAnimationFrame(PassOwnPtr<RequestAnimationFrameCallback> callback)
1513 {
1514     callback->m_useLegacyTimeBase = true;
1515     if (Document* d = document())
1516         return d->requestAnimationFrame(callback);
1517     return 0;
1518 }
1519 
cancelAnimationFrame(int id)1520 void LocalDOMWindow::cancelAnimationFrame(int id)
1521 {
1522     if (Document* d = document())
1523         d->cancelAnimationFrame(id);
1524 }
1525 
css() const1526 DOMWindowCSS& LocalDOMWindow::css() const
1527 {
1528     if (!m_css)
1529         m_css = DOMWindowCSS::create();
1530     return *m_css;
1531 }
1532 
didAddStorageEventListener(LocalDOMWindow * window)1533 static void didAddStorageEventListener(LocalDOMWindow* window)
1534 {
1535     // Creating these WebCore::Storage objects informs the system that we'd like to receive
1536     // notifications about storage events that might be triggered in other processes. Rather
1537     // than subscribe to these notifications explicitly, we subscribe to them implicitly to
1538     // simplify the work done by the system.
1539     window->localStorage(IGNORE_EXCEPTION);
1540     window->sessionStorage(IGNORE_EXCEPTION);
1541 }
1542 
addEventListener(const AtomicString & eventType,PassRefPtr<EventListener> listener,bool useCapture)1543 bool LocalDOMWindow::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
1544 {
1545     if (!EventTarget::addEventListener(eventType, listener, useCapture))
1546         return false;
1547 
1548     if (m_frame && m_frame->host())
1549         m_frame->host()->eventHandlerRegistry().didAddEventHandler(*this, eventType);
1550 
1551     if (Document* document = this->document()) {
1552         document->addListenerTypeIfNeeded(eventType);
1553         if (isTouchEventType(eventType))
1554             document->didAddTouchEventHandler(document);
1555         else if (eventType == EventTypeNames::storage)
1556             didAddStorageEventListener(this);
1557     }
1558 
1559     lifecycleNotifier().notifyAddEventListener(this, eventType);
1560 
1561     if (eventType == EventTypeNames::unload) {
1562         UseCounter::count(document(), UseCounter::DocumentUnloadRegistered);
1563         addUnloadEventListener(this);
1564     } else if (eventType == EventTypeNames::beforeunload) {
1565         UseCounter::count(document(), UseCounter::DocumentBeforeUnloadRegistered);
1566         if (allowsBeforeUnloadListeners(this)) {
1567             // This is confusingly named. It doesn't actually add the listener. It just increments a count
1568             // so that we know we have listeners registered for the purposes of determining if we can
1569             // fast terminate the renderer process.
1570             addBeforeUnloadEventListener(this);
1571         } else {
1572             // Subframes return false from allowsBeforeUnloadListeners.
1573             UseCounter::count(document(), UseCounter::SubFrameBeforeUnloadRegistered);
1574         }
1575     }
1576 
1577     return true;
1578 }
1579 
removeEventListener(const AtomicString & eventType,EventListener * listener,bool useCapture)1580 bool LocalDOMWindow::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
1581 {
1582     if (!EventTarget::removeEventListener(eventType, listener, useCapture))
1583         return false;
1584 
1585     if (m_frame && m_frame->host())
1586         m_frame->host()->eventHandlerRegistry().didRemoveEventHandler(*this, eventType);
1587 
1588     if (Document* document = this->document()) {
1589         if (isTouchEventType(eventType))
1590             document->didRemoveTouchEventHandler(document);
1591     }
1592 
1593     lifecycleNotifier().notifyRemoveEventListener(this, eventType);
1594 
1595     if (eventType == EventTypeNames::unload) {
1596         removeUnloadEventListener(this);
1597     } else if (eventType == EventTypeNames::beforeunload && allowsBeforeUnloadListeners(this)) {
1598         removeBeforeUnloadEventListener(this);
1599     }
1600 
1601     return true;
1602 }
1603 
dispatchLoadEvent()1604 void LocalDOMWindow::dispatchLoadEvent()
1605 {
1606     RefPtrWillBeRawPtr<Event> loadEvent(Event::create(EventTypeNames::load));
1607     if (m_frame && m_frame->loader().documentLoader() && !m_frame->loader().documentLoader()->timing()->loadEventStart()) {
1608         // The DocumentLoader (and thus its DocumentLoadTiming) might get destroyed while dispatching
1609         // the event, so protect it to prevent writing the end time into freed memory.
1610         RefPtr<DocumentLoader> documentLoader = m_frame->loader().documentLoader();
1611         DocumentLoadTiming* timing = documentLoader->timing();
1612         timing->markLoadEventStart();
1613         dispatchEvent(loadEvent, document());
1614         timing->markLoadEventEnd();
1615     } else
1616         dispatchEvent(loadEvent, document());
1617 
1618     // For load events, send a separate load event to the enclosing frame only.
1619     // This is a DOM extension and is independent of bubbling/capturing rules of
1620     // the DOM.
1621     FrameOwner* owner = m_frame ? m_frame->owner() : 0;
1622     if (owner)
1623         owner->dispatchLoad();
1624 
1625     TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "MarkLoad", "data", InspectorMarkLoadEvent::data(frame()));
1626     // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
1627     InspectorInstrumentation::loadEventFired(frame());
1628 }
1629 
dispatchEvent(PassRefPtrWillBeRawPtr<Event> prpEvent,PassRefPtrWillBeRawPtr<EventTarget> prpTarget)1630 bool LocalDOMWindow::dispatchEvent(PassRefPtrWillBeRawPtr<Event> prpEvent, PassRefPtrWillBeRawPtr<EventTarget> prpTarget)
1631 {
1632     ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
1633 
1634     RefPtrWillBeRawPtr<EventTarget> protect(this);
1635     RefPtrWillBeRawPtr<Event> event = prpEvent;
1636 
1637     event->setTarget(prpTarget ? prpTarget : this);
1638     event->setCurrentTarget(this);
1639     event->setEventPhase(Event::AT_TARGET);
1640 
1641     TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "EventDispatch", "type", event->type().ascii());
1642     // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
1643     InspectorInstrumentationCookie cookie = InspectorInstrumentation::willDispatchEventOnWindow(frame(), *event, this);
1644 
1645     bool result = fireEventListeners(event.get());
1646 
1647     InspectorInstrumentation::didDispatchEventOnWindow(cookie);
1648 
1649     return result;
1650 }
1651 
removeAllEventListenersInternal(BroadcastListenerRemoval mode)1652 void LocalDOMWindow::removeAllEventListenersInternal(BroadcastListenerRemoval mode)
1653 {
1654     EventTarget::removeAllEventListeners();
1655 
1656     lifecycleNotifier().notifyRemoveAllEventListeners(this);
1657 
1658     if (mode == DoBroadcastListenerRemoval) {
1659         if (m_frame && m_frame->host())
1660             m_frame->host()->eventHandlerRegistry().didRemoveAllEventHandlers(*this);
1661 
1662         if (Document* document = this->document())
1663             document->didClearTouchEventHandlers(document);
1664     }
1665 
1666     removeAllUnloadEventListeners(this);
1667     removeAllBeforeUnloadEventListeners(this);
1668 }
1669 
removeAllEventListeners()1670 void LocalDOMWindow::removeAllEventListeners()
1671 {
1672     removeAllEventListenersInternal(DoBroadcastListenerRemoval);
1673 }
1674 
finishedLoading()1675 void LocalDOMWindow::finishedLoading()
1676 {
1677     if (m_shouldPrintWhenFinishedLoading) {
1678         m_shouldPrintWhenFinishedLoading = false;
1679         print();
1680     }
1681 }
1682 
setLocation(const String & urlString,LocalDOMWindow * callingWindow,LocalDOMWindow * enteredWindow,SetLocationLocking locking)1683 void LocalDOMWindow::setLocation(const String& urlString, LocalDOMWindow* callingWindow, LocalDOMWindow* enteredWindow, SetLocationLocking locking)
1684 {
1685     if (!isCurrentlyDisplayedInFrame())
1686         return;
1687 
1688     Document* activeDocument = callingWindow->document();
1689     if (!activeDocument)
1690         return;
1691 
1692     ASSERT(m_frame);
1693     if (!activeDocument->canNavigate(*m_frame))
1694         return;
1695 
1696     LocalFrame* firstFrame = enteredWindow->frame();
1697     if (!firstFrame)
1698         return;
1699 
1700     KURL completedURL = firstFrame->document()->completeURL(urlString);
1701     if (completedURL.isNull())
1702         return;
1703 
1704     if (isInsecureScriptAccess(*callingWindow, completedURL))
1705         return;
1706 
1707     // We want a new history item if we are processing a user gesture.
1708     m_frame->navigationScheduler().scheduleLocationChange(activeDocument,
1709         // FIXME: What if activeDocument()->frame() is 0?
1710         completedURL, Referrer(activeDocument->outgoingReferrer(), activeDocument->referrerPolicy()),
1711         locking != LockHistoryBasedOnGestureState);
1712 }
1713 
printErrorMessage(const String & message)1714 void LocalDOMWindow::printErrorMessage(const String& message)
1715 {
1716     if (message.isEmpty())
1717         return;
1718 
1719     frameConsole()->addMessage(JSMessageSource, ErrorMessageLevel, message);
1720 }
1721 
1722 // FIXME: Once we're throwing exceptions for cross-origin access violations, we will always sanitize the target
1723 // frame details, so we can safely combine 'crossDomainAccessErrorMessage' with this method after considering
1724 // exactly which details may be exposed to JavaScript.
1725 //
1726 // http://crbug.com/17325
sanitizedCrossDomainAccessErrorMessage(LocalDOMWindow * callingWindow)1727 String LocalDOMWindow::sanitizedCrossDomainAccessErrorMessage(LocalDOMWindow* callingWindow)
1728 {
1729     if (!callingWindow || !callingWindow->document())
1730         return String();
1731 
1732     const KURL& callingWindowURL = callingWindow->document()->url();
1733     if (callingWindowURL.isNull())
1734         return String();
1735 
1736     ASSERT(!callingWindow->document()->securityOrigin()->canAccess(document()->securityOrigin()));
1737 
1738     SecurityOrigin* activeOrigin = callingWindow->document()->securityOrigin();
1739     String message = "Blocked a frame with origin \"" + activeOrigin->toString() + "\" from accessing a cross-origin frame.";
1740 
1741     // FIXME: Evaluate which details from 'crossDomainAccessErrorMessage' may safely be reported to JavaScript.
1742 
1743     return message;
1744 }
1745 
crossDomainAccessErrorMessage(LocalDOMWindow * callingWindow)1746 String LocalDOMWindow::crossDomainAccessErrorMessage(LocalDOMWindow* callingWindow)
1747 {
1748     if (!callingWindow || !callingWindow->document())
1749         return String();
1750 
1751     const KURL& callingWindowURL = callingWindow->document()->url();
1752     if (callingWindowURL.isNull())
1753         return String();
1754 
1755     ASSERT(!callingWindow->document()->securityOrigin()->canAccess(document()->securityOrigin()));
1756 
1757     // FIXME: This message, and other console messages, have extra newlines. Should remove them.
1758     SecurityOrigin* activeOrigin = callingWindow->document()->securityOrigin();
1759     SecurityOrigin* targetOrigin = document()->securityOrigin();
1760     String message = "Blocked a frame with origin \"" + activeOrigin->toString() + "\" from accessing a frame with origin \"" + targetOrigin->toString() + "\". ";
1761 
1762     // Sandbox errors: Use the origin of the frames' location, rather than their actual origin (since we know that at least one will be "null").
1763     KURL activeURL = callingWindow->document()->url();
1764     KURL targetURL = document()->url();
1765     if (document()->isSandboxed(SandboxOrigin) || callingWindow->document()->isSandboxed(SandboxOrigin)) {
1766         message = "Blocked a frame at \"" + SecurityOrigin::create(activeURL)->toString() + "\" from accessing a frame at \"" + SecurityOrigin::create(targetURL)->toString() + "\". ";
1767         if (document()->isSandboxed(SandboxOrigin) && callingWindow->document()->isSandboxed(SandboxOrigin))
1768             return "Sandbox access violation: " + message + " Both frames are sandboxed and lack the \"allow-same-origin\" flag.";
1769         if (document()->isSandboxed(SandboxOrigin))
1770             return "Sandbox access violation: " + message + " The frame being accessed is sandboxed and lacks the \"allow-same-origin\" flag.";
1771         return "Sandbox access violation: " + message + " The frame requesting access is sandboxed and lacks the \"allow-same-origin\" flag.";
1772     }
1773 
1774     // 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:'.
1775     if (targetOrigin->protocol() != activeOrigin->protocol())
1776         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";
1777 
1778     // 'document.domain' errors.
1779     if (targetOrigin->domainWasSetInDOM() && activeOrigin->domainWasSetInDOM())
1780         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.";
1781     if (activeOrigin->domainWasSetInDOM())
1782         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.";
1783     if (targetOrigin->domainWasSetInDOM())
1784         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.";
1785 
1786     // Default.
1787     return message + "Protocols, domains, and ports must match.";
1788 }
1789 
isInsecureScriptAccess(LocalDOMWindow & callingWindow,const String & urlString)1790 bool LocalDOMWindow::isInsecureScriptAccess(LocalDOMWindow& callingWindow, const String& urlString)
1791 {
1792     if (!protocolIsJavaScript(urlString))
1793         return false;
1794 
1795     // If this LocalDOMWindow isn't currently active in the LocalFrame, then there's no
1796     // way we should allow the access.
1797     // FIXME: Remove this check if we're able to disconnect LocalDOMWindow from
1798     // LocalFrame on navigation: https://bugs.webkit.org/show_bug.cgi?id=62054
1799     if (isCurrentlyDisplayedInFrame()) {
1800         // FIXME: Is there some way to eliminate the need for a separate "callingWindow == this" check?
1801         if (&callingWindow == this)
1802             return false;
1803 
1804         // FIXME: The name canAccess seems to be a roundabout way to ask "can execute script".
1805         // Can we name the SecurityOrigin function better to make this more clear?
1806         if (callingWindow.document()->securityOrigin()->canAccess(document()->securityOrigin()))
1807             return false;
1808     }
1809 
1810     printErrorMessage(crossDomainAccessErrorMessage(&callingWindow));
1811     return true;
1812 }
1813 
open(const String & urlString,const AtomicString & frameName,const String & windowFeaturesString,LocalDOMWindow * callingWindow,LocalDOMWindow * enteredWindow)1814 PassRefPtrWillBeRawPtr<LocalDOMWindow> LocalDOMWindow::open(const String& urlString, const AtomicString& frameName, const String& windowFeaturesString,
1815     LocalDOMWindow* callingWindow, LocalDOMWindow* enteredWindow)
1816 {
1817     if (!isCurrentlyDisplayedInFrame())
1818         return nullptr;
1819     Document* activeDocument = callingWindow->document();
1820     if (!activeDocument)
1821         return nullptr;
1822     LocalFrame* firstFrame = enteredWindow->frame();
1823     if (!firstFrame)
1824         return nullptr;
1825 
1826     if (!enteredWindow->allowPopUp()) {
1827         // Because FrameTree::find() returns true for empty strings, we must check for empty frame names.
1828         // Otherwise, illegitimate window.open() calls with no name will pass right through the popup blocker.
1829         if (frameName.isEmpty() || !m_frame->tree().find(frameName))
1830             return nullptr;
1831     }
1832 
1833     // Get the target frame for the special cases of _top and _parent.
1834     // In those cases, we schedule a location change right now and return early.
1835     Frame* targetFrame = 0;
1836     if (frameName == "_top")
1837         targetFrame = m_frame->tree().top();
1838     else if (frameName == "_parent") {
1839         if (Frame* parent = m_frame->tree().parent())
1840             targetFrame = parent;
1841         else
1842             targetFrame = m_frame;
1843     }
1844     // FIXME: Navigating RemoteFrames is not yet supported.
1845     if (targetFrame && targetFrame->isLocalFrame()) {
1846         if (!activeDocument->canNavigate(*targetFrame))
1847             return nullptr;
1848 
1849         KURL completedURL = firstFrame->document()->completeURL(urlString);
1850 
1851         if (targetFrame->domWindow()->isInsecureScriptAccess(*callingWindow, completedURL))
1852             return targetFrame->domWindow();
1853 
1854         if (urlString.isEmpty())
1855             return targetFrame->domWindow();
1856 
1857         // For whatever reason, Firefox uses the first window rather than the active window to
1858         // determine the outgoing referrer. We replicate that behavior here.
1859         toLocalFrame(targetFrame)->navigationScheduler().scheduleLocationChange(
1860             activeDocument,
1861             completedURL,
1862             Referrer(firstFrame->document()->outgoingReferrer(), firstFrame->document()->referrerPolicy()),
1863             false);
1864         return targetFrame->domWindow();
1865     }
1866 
1867     WindowFeatures windowFeatures(windowFeaturesString);
1868     LocalFrame* result = createWindow(urlString, frameName, windowFeatures, *callingWindow, *firstFrame, *m_frame);
1869     return result ? result->domWindow() : 0;
1870 }
1871 
showModalDialog(const String & urlString,const String & dialogFeaturesString,LocalDOMWindow * callingWindow,LocalDOMWindow * enteredWindow,PrepareDialogFunction function,void * functionContext)1872 void LocalDOMWindow::showModalDialog(const String& urlString, const String& dialogFeaturesString,
1873     LocalDOMWindow* callingWindow, LocalDOMWindow* enteredWindow, PrepareDialogFunction function, void* functionContext)
1874 {
1875     if (!isCurrentlyDisplayedInFrame())
1876         return;
1877     LocalFrame* activeFrame = callingWindow->frame();
1878     if (!activeFrame)
1879         return;
1880     LocalFrame* firstFrame = enteredWindow->frame();
1881     if (!firstFrame)
1882         return;
1883 
1884     if (!canShowModalDialogNow(m_frame) || !enteredWindow->allowPopUp())
1885         return;
1886 
1887     UseCounter::countDeprecation(this, UseCounter::ShowModalDialog);
1888 
1889     WindowFeatures windowFeatures(dialogFeaturesString, screenAvailableRect(m_frame->view()));
1890     LocalFrame* dialogFrame = createWindow(urlString, emptyAtom, windowFeatures,
1891         *callingWindow, *firstFrame, *m_frame, function, functionContext);
1892     if (!dialogFrame)
1893         return;
1894     UserGestureIndicatorDisabler disabler;
1895     dialogFrame->host()->chrome().runModal();
1896 }
1897 
anonymousIndexedGetter(uint32_t index)1898 LocalDOMWindow* LocalDOMWindow::anonymousIndexedGetter(uint32_t index)
1899 {
1900     LocalFrame* frame = this->frame();
1901     if (!frame)
1902         return 0;
1903 
1904     Frame* child = frame->tree().scopedChild(index);
1905     if (child)
1906         return child->domWindow();
1907 
1908     return 0;
1909 }
1910 
lifecycleNotifier()1911 DOMWindowLifecycleNotifier& LocalDOMWindow::lifecycleNotifier()
1912 {
1913     return static_cast<DOMWindowLifecycleNotifier&>(LifecycleContext<LocalDOMWindow>::lifecycleNotifier());
1914 }
1915 
createLifecycleNotifier()1916 PassOwnPtr<LifecycleNotifier<LocalDOMWindow> > LocalDOMWindow::createLifecycleNotifier()
1917 {
1918     return DOMWindowLifecycleNotifier::create(this);
1919 }
1920 
trace(Visitor * visitor)1921 void LocalDOMWindow::trace(Visitor* visitor)
1922 {
1923     visitor->trace(m_document);
1924     visitor->trace(m_screen);
1925     visitor->trace(m_history);
1926     visitor->trace(m_locationbar);
1927     visitor->trace(m_menubar);
1928     visitor->trace(m_personalbar);
1929     visitor->trace(m_scrollbars);
1930     visitor->trace(m_statusbar);
1931     visitor->trace(m_toolbar);
1932     visitor->trace(m_console);
1933     visitor->trace(m_navigator);
1934     visitor->trace(m_location);
1935     visitor->trace(m_media);
1936     visitor->trace(m_sessionStorage);
1937     visitor->trace(m_localStorage);
1938     visitor->trace(m_applicationCache);
1939     visitor->trace(m_performance);
1940     visitor->trace(m_css);
1941     visitor->trace(m_eventQueue);
1942     WillBeHeapSupplementable<LocalDOMWindow>::trace(visitor);
1943     EventTargetWithInlineData::trace(visitor);
1944 }
1945 
1946 } // namespace WebCore
1947