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