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