| /* |
| * Copyright (C) 2006, 2007, 2008, 2010 Apple Inc. All rights reserved. |
| * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include "core/frame/LocalDOMWindow.h" |
| |
| #include "bindings/core/v8/Dictionary.h" |
| #include "bindings/core/v8/ExceptionMessages.h" |
| #include "bindings/core/v8/ExceptionState.h" |
| #include "bindings/core/v8/ExceptionStatePlaceholder.h" |
| #include "bindings/core/v8/ScriptCallStackFactory.h" |
| #include "bindings/core/v8/ScriptController.h" |
| #include "bindings/core/v8/SerializedScriptValue.h" |
| #include "bindings/core/v8/V8DOMActivityLogger.h" |
| #include "core/css/CSSComputedStyleDeclaration.h" |
| #include "core/css/CSSRuleList.h" |
| #include "core/css/DOMWindowCSS.h" |
| #include "core/css/MediaQueryList.h" |
| #include "core/css/MediaQueryMatcher.h" |
| #include "core/css/StyleMedia.h" |
| #include "core/css/resolver/StyleResolver.h" |
| #include "core/dom/ContextFeatures.h" |
| #include "core/dom/DOMImplementation.h" |
| #include "core/dom/Document.h" |
| #include "core/dom/Element.h" |
| #include "core/dom/ExceptionCode.h" |
| #include "core/dom/ExecutionContext.h" |
| #include "core/dom/RequestAnimationFrameCallback.h" |
| #include "core/editing/Editor.h" |
| #include "core/events/DOMWindowEventQueue.h" |
| #include "core/events/EventListener.h" |
| #include "core/events/HashChangeEvent.h" |
| #include "core/events/MessageEvent.h" |
| #include "core/events/PageTransitionEvent.h" |
| #include "core/events/PopStateEvent.h" |
| #include "core/frame/BarProp.h" |
| #include "core/frame/Console.h" |
| #include "core/frame/DOMWindowLifecycleNotifier.h" |
| #include "core/frame/EventHandlerRegistry.h" |
| #include "core/frame/FrameConsole.h" |
| #include "core/frame/FrameHost.h" |
| #include "core/frame/FrameView.h" |
| #include "core/frame/History.h" |
| #include "core/frame/LocalFrame.h" |
| #include "core/frame/Location.h" |
| #include "core/frame/Navigator.h" |
| #include "core/frame/Screen.h" |
| #include "core/frame/Settings.h" |
| #include "core/frame/WebKitPoint.h" |
| #include "core/html/HTMLFrameOwnerElement.h" |
| #include "core/inspector/ConsoleMessage.h" |
| #include "core/inspector/InspectorInstrumentation.h" |
| #include "core/inspector/InspectorTraceEvents.h" |
| #include "core/inspector/ScriptCallStack.h" |
| #include "core/loader/DocumentLoader.h" |
| #include "core/loader/FrameLoadRequest.h" |
| #include "core/loader/FrameLoader.h" |
| #include "core/loader/FrameLoaderClient.h" |
| #include "core/loader/MixedContentChecker.h" |
| #include "core/loader/SinkDocument.h" |
| #include "core/loader/appcache/ApplicationCache.h" |
| #include "core/page/BackForwardClient.h" |
| #include "core/page/Chrome.h" |
| #include "core/page/ChromeClient.h" |
| #include "core/page/CreateWindow.h" |
| #include "core/page/EventHandler.h" |
| #include "core/page/FrameTree.h" |
| #include "core/page/Page.h" |
| #include "core/page/WindowFeatures.h" |
| #include "core/page/WindowFocusAllowedIndicator.h" |
| #include "core/page/scrolling/ScrollingCoordinator.h" |
| #include "core/storage/Storage.h" |
| #include "core/storage/StorageArea.h" |
| #include "core/storage/StorageNamespace.h" |
| #include "core/timing/Performance.h" |
| #include "platform/EventDispatchForbiddenScope.h" |
| #include "platform/PlatformScreen.h" |
| #include "platform/RuntimeEnabledFeatures.h" |
| #include "platform/UserGestureIndicator.h" |
| #include "platform/geometry/FloatRect.h" |
| #include "platform/graphics/media/MediaPlayer.h" |
| #include "platform/weborigin/KURL.h" |
| #include "platform/weborigin/SecurityOrigin.h" |
| #include "platform/weborigin/SecurityPolicy.h" |
| #include "public/platform/Platform.h" |
| #include "wtf/MainThread.h" |
| #include "wtf/MathExtras.h" |
| #include "wtf/text/WTFString.h" |
| #include <algorithm> |
| |
| using std::min; |
| using std::max; |
| |
| namespace blink { |
| |
| class PostMessageTimer FINAL : public SuspendableTimer { |
| public: |
| PostMessageTimer(LocalDOMWindow& window, PassRefPtr<SerializedScriptValue> message, const String& sourceOrigin, PassRefPtrWillBeRawPtr<LocalDOMWindow> source, PassOwnPtr<MessagePortChannelArray> channels, SecurityOrigin* targetOrigin, PassRefPtrWillBeRawPtr<ScriptCallStack> stackTrace, UserGestureToken* userGestureToken) |
| : SuspendableTimer(window.document()) |
| , m_window(&window) |
| , m_message(message) |
| , m_origin(sourceOrigin) |
| , m_source(source) |
| , m_channels(channels) |
| , m_targetOrigin(targetOrigin) |
| , m_stackTrace(stackTrace) |
| , m_userGestureToken(userGestureToken) |
| { |
| m_asyncOperationId = InspectorInstrumentation::traceAsyncOperationStarting(executionContext(), "postMessage"); |
| } |
| |
| PassRefPtrWillBeRawPtr<MessageEvent> event() |
| { |
| return MessageEvent::create(m_channels.release(), m_message, m_origin, String(), m_source.get()); |
| |
| } |
| SecurityOrigin* targetOrigin() const { return m_targetOrigin.get(); } |
| ScriptCallStack* stackTrace() const { return m_stackTrace.get(); } |
| UserGestureToken* userGestureToken() const { return m_userGestureToken.get(); } |
| |
| private: |
| virtual void fired() OVERRIDE |
| { |
| InspectorInstrumentationCookie cookie = InspectorInstrumentation::traceAsyncOperationCompletedCallbackStarting(executionContext(), m_asyncOperationId); |
| m_window->postMessageTimerFired(this); |
| // This object is deleted now. |
| InspectorInstrumentation::traceAsyncCallbackCompleted(cookie); |
| } |
| |
| // FIXME: Oilpan: This raw pointer is safe because the PostMessageTimer is |
| // owned by the LocalDOMWindow. Ideally PostMessageTimer should be moved to |
| // the heap and use Member<LocalDOMWindow>. |
| LocalDOMWindow* m_window; |
| RefPtr<SerializedScriptValue> m_message; |
| String m_origin; |
| RefPtrWillBePersistent<LocalDOMWindow> m_source; |
| OwnPtr<MessagePortChannelArray> m_channels; |
| RefPtr<SecurityOrigin> m_targetOrigin; |
| RefPtrWillBePersistent<ScriptCallStack> m_stackTrace; |
| RefPtr<UserGestureToken> m_userGestureToken; |
| int m_asyncOperationId; |
| }; |
| |
| static void disableSuddenTermination() |
| { |
| blink::Platform::current()->suddenTerminationChanged(false); |
| } |
| |
| static void enableSuddenTermination() |
| { |
| blink::Platform::current()->suddenTerminationChanged(true); |
| } |
| |
| typedef HashCountedSet<LocalDOMWindow*> DOMWindowSet; |
| |
| static DOMWindowSet& windowsWithUnloadEventListeners() |
| { |
| DEFINE_STATIC_LOCAL(DOMWindowSet, windowsWithUnloadEventListeners, ()); |
| return windowsWithUnloadEventListeners; |
| } |
| |
| static DOMWindowSet& windowsWithBeforeUnloadEventListeners() |
| { |
| DEFINE_STATIC_LOCAL(DOMWindowSet, windowsWithBeforeUnloadEventListeners, ()); |
| return windowsWithBeforeUnloadEventListeners; |
| } |
| |
| static void addUnloadEventListener(LocalDOMWindow* domWindow) |
| { |
| DOMWindowSet& set = windowsWithUnloadEventListeners(); |
| if (set.isEmpty()) |
| disableSuddenTermination(); |
| set.add(domWindow); |
| } |
| |
| static void removeUnloadEventListener(LocalDOMWindow* domWindow) |
| { |
| DOMWindowSet& set = windowsWithUnloadEventListeners(); |
| DOMWindowSet::iterator it = set.find(domWindow); |
| if (it == set.end()) |
| return; |
| set.remove(it); |
| if (set.isEmpty()) |
| enableSuddenTermination(); |
| } |
| |
| static void removeAllUnloadEventListeners(LocalDOMWindow* domWindow) |
| { |
| DOMWindowSet& set = windowsWithUnloadEventListeners(); |
| DOMWindowSet::iterator it = set.find(domWindow); |
| if (it == set.end()) |
| return; |
| set.removeAll(it); |
| if (set.isEmpty()) |
| enableSuddenTermination(); |
| } |
| |
| static void addBeforeUnloadEventListener(LocalDOMWindow* domWindow) |
| { |
| DOMWindowSet& set = windowsWithBeforeUnloadEventListeners(); |
| if (set.isEmpty()) |
| disableSuddenTermination(); |
| set.add(domWindow); |
| } |
| |
| static void removeBeforeUnloadEventListener(LocalDOMWindow* domWindow) |
| { |
| DOMWindowSet& set = windowsWithBeforeUnloadEventListeners(); |
| DOMWindowSet::iterator it = set.find(domWindow); |
| if (it == set.end()) |
| return; |
| set.remove(it); |
| if (set.isEmpty()) |
| enableSuddenTermination(); |
| } |
| |
| static void removeAllBeforeUnloadEventListeners(LocalDOMWindow* domWindow) |
| { |
| DOMWindowSet& set = windowsWithBeforeUnloadEventListeners(); |
| DOMWindowSet::iterator it = set.find(domWindow); |
| if (it == set.end()) |
| return; |
| set.removeAll(it); |
| if (set.isEmpty()) |
| enableSuddenTermination(); |
| } |
| |
| static bool allowsBeforeUnloadListeners(LocalDOMWindow* window) |
| { |
| ASSERT_ARG(window, window); |
| LocalFrame* frame = window->frame(); |
| if (!frame) |
| return false; |
| return frame->isMainFrame(); |
| } |
| |
| unsigned LocalDOMWindow::pendingUnloadEventListeners() const |
| { |
| return windowsWithUnloadEventListeners().count(const_cast<LocalDOMWindow*>(this)); |
| } |
| |
| // This function: |
| // 1) Validates the pending changes are not changing any value to NaN; in that case keep original value. |
| // 2) Constrains the window rect to the minimum window size and no bigger than the float rect's dimensions. |
| // 3) Constrains the window rect to within the top and left boundaries of the available screen rect. |
| // 4) Constrains the window rect to within the bottom and right boundaries of the available screen rect. |
| // 5) Translate the window rect coordinates to be within the coordinate space of the screen. |
| FloatRect LocalDOMWindow::adjustWindowRect(LocalFrame& frame, const FloatRect& pendingChanges) |
| { |
| FrameHost* host = frame.host(); |
| ASSERT(host); |
| |
| FloatRect screen = screenAvailableRect(frame.view()); |
| FloatRect window = host->chrome().windowRect(); |
| |
| // Make sure we're in a valid state before adjusting dimensions. |
| ASSERT(std::isfinite(screen.x())); |
| ASSERT(std::isfinite(screen.y())); |
| ASSERT(std::isfinite(screen.width())); |
| ASSERT(std::isfinite(screen.height())); |
| ASSERT(std::isfinite(window.x())); |
| ASSERT(std::isfinite(window.y())); |
| ASSERT(std::isfinite(window.width())); |
| ASSERT(std::isfinite(window.height())); |
| |
| // Update window values if new requested values are not NaN. |
| if (!std::isnan(pendingChanges.x())) |
| window.setX(pendingChanges.x()); |
| if (!std::isnan(pendingChanges.y())) |
| window.setY(pendingChanges.y()); |
| if (!std::isnan(pendingChanges.width())) |
| window.setWidth(pendingChanges.width()); |
| if (!std::isnan(pendingChanges.height())) |
| window.setHeight(pendingChanges.height()); |
| |
| FloatSize minimumSize = host->chrome().client().minimumWindowSize(); |
| // Let size 0 pass through, since that indicates default size, not minimum size. |
| if (window.width()) |
| window.setWidth(min(max(minimumSize.width(), window.width()), screen.width())); |
| if (window.height()) |
| window.setHeight(min(max(minimumSize.height(), window.height()), screen.height())); |
| |
| // Constrain the window position within the valid screen area. |
| window.setX(max(screen.x(), min(window.x(), screen.maxX() - window.width()))); |
| window.setY(max(screen.y(), min(window.y(), screen.maxY() - window.height()))); |
| |
| return window; |
| } |
| |
| bool LocalDOMWindow::allowPopUp(LocalFrame& firstFrame) |
| { |
| if (UserGestureIndicator::processingUserGesture()) |
| return true; |
| |
| Settings* settings = firstFrame.settings(); |
| return settings && settings->javaScriptCanOpenWindowsAutomatically(); |
| } |
| |
| bool LocalDOMWindow::allowPopUp() |
| { |
| return m_frame && allowPopUp(*m_frame); |
| } |
| |
| bool LocalDOMWindow::canShowModalDialogNow(const LocalFrame* frame) |
| { |
| if (!frame) |
| return false; |
| FrameHost* host = frame->host(); |
| if (!host) |
| return false; |
| return host->chrome().canRunModalNow(); |
| } |
| |
| LocalDOMWindow::LocalDOMWindow(LocalFrame& frame) |
| : FrameDestructionObserver(&frame) |
| , m_shouldPrintWhenFinishedLoading(false) |
| #if ENABLE(ASSERT) |
| , m_hasBeenReset(false) |
| #endif |
| { |
| ScriptWrappable::init(this); |
| } |
| |
| void LocalDOMWindow::clearDocument() |
| { |
| if (!m_document) |
| return; |
| |
| if (m_document->isActive()) { |
| // FIXME: We don't call willRemove here. Why is that OK? |
| // This detach() call is also mostly redundant. Most of the calls to |
| // this function come via DocumentLoader::createWriterFor, which |
| // always detaches the previous Document first. Only XSLTProcessor |
| // depends on this detach() call, so it seems like there's some room |
| // for cleanup. |
| m_document->detach(); |
| } |
| |
| // FIXME: This should be part of ActiveDOMObject shutdown |
| clearEventQueue(); |
| |
| m_document->clearDOMWindow(); |
| m_document = nullptr; |
| } |
| |
| void LocalDOMWindow::clearEventQueue() |
| { |
| if (!m_eventQueue) |
| return; |
| m_eventQueue->close(); |
| m_eventQueue.clear(); |
| } |
| |
| void LocalDOMWindow::acceptLanguagesChanged() |
| { |
| if (m_navigator) |
| m_navigator->setLanguagesChanged(); |
| |
| dispatchEvent(Event::create(EventTypeNames::languagechange)); |
| } |
| |
| PassRefPtrWillBeRawPtr<Document> LocalDOMWindow::createDocument(const String& mimeType, const DocumentInit& init, bool forceXHTML) |
| { |
| RefPtrWillBeRawPtr<Document> document = nullptr; |
| if (forceXHTML) { |
| // This is a hack for XSLTProcessor. See XSLTProcessor::createDocumentFromSource(). |
| document = Document::create(init); |
| } else { |
| document = DOMImplementation::createDocument(mimeType, init, init.frame() ? init.frame()->inViewSourceMode() : false); |
| if (document->isPluginDocument() && document->isSandboxed(SandboxPlugins)) |
| document = SinkDocument::create(init); |
| } |
| |
| return document.release(); |
| } |
| |
| PassRefPtrWillBeRawPtr<Document> LocalDOMWindow::installNewDocument(const String& mimeType, const DocumentInit& init, bool forceXHTML) |
| { |
| ASSERT(init.frame() == m_frame); |
| |
| clearDocument(); |
| |
| m_document = createDocument(mimeType, init, forceXHTML); |
| m_eventQueue = DOMWindowEventQueue::create(m_document.get()); |
| m_document->attach(); |
| |
| if (!m_frame) |
| return m_document; |
| |
| m_frame->script().updateDocument(); |
| m_document->updateViewportDescription(); |
| |
| if (m_frame->page() && m_frame->view()) { |
| if (ScrollingCoordinator* scrollingCoordinator = m_frame->page()->scrollingCoordinator()) { |
| scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_frame->view(), HorizontalScrollbar); |
| scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_frame->view(), VerticalScrollbar); |
| scrollingCoordinator->scrollableAreaScrollLayerDidChange(m_frame->view()); |
| } |
| } |
| |
| m_frame->selection().updateSecureKeyboardEntryIfActive(); |
| return m_document; |
| } |
| |
| EventQueue* LocalDOMWindow::eventQueue() const |
| { |
| return m_eventQueue.get(); |
| } |
| |
| void LocalDOMWindow::enqueueWindowEvent(PassRefPtrWillBeRawPtr<Event> event) |
| { |
| if (!m_eventQueue) |
| return; |
| event->setTarget(this); |
| m_eventQueue->enqueueEvent(event); |
| } |
| |
| void LocalDOMWindow::enqueueDocumentEvent(PassRefPtrWillBeRawPtr<Event> event) |
| { |
| if (!m_eventQueue) |
| return; |
| event->setTarget(m_document.get()); |
| m_eventQueue->enqueueEvent(event); |
| } |
| |
| void LocalDOMWindow::dispatchWindowLoadEvent() |
| { |
| ASSERT(!EventDispatchForbiddenScope::isEventDispatchForbidden()); |
| dispatchLoadEvent(); |
| } |
| |
| void LocalDOMWindow::documentWasClosed() |
| { |
| dispatchWindowLoadEvent(); |
| enqueuePageshowEvent(PageshowEventNotPersisted); |
| if (m_pendingStateObject) |
| enqueuePopstateEvent(m_pendingStateObject.release()); |
| } |
| |
| void LocalDOMWindow::enqueuePageshowEvent(PageshowEventPersistence persisted) |
| { |
| // FIXME: https://bugs.webkit.org/show_bug.cgi?id=36334 Pageshow event needs to fire asynchronously. |
| // As per spec pageshow must be triggered asynchronously. |
| // However to be compatible with other browsers blink fires pageshow synchronously. |
| dispatchEvent(PageTransitionEvent::create(EventTypeNames::pageshow, persisted), m_document.get()); |
| } |
| |
| void LocalDOMWindow::enqueueHashchangeEvent(const String& oldURL, const String& newURL) |
| { |
| enqueueWindowEvent(HashChangeEvent::create(oldURL, newURL)); |
| } |
| |
| void LocalDOMWindow::enqueuePopstateEvent(PassRefPtr<SerializedScriptValue> stateObject) |
| { |
| if (!ContextFeatures::pushStateEnabled(document())) |
| return; |
| |
| // FIXME: https://bugs.webkit.org/show_bug.cgi?id=36202 Popstate event needs to fire asynchronously |
| dispatchEvent(PopStateEvent::create(stateObject, &history())); |
| } |
| |
| void LocalDOMWindow::statePopped(PassRefPtr<SerializedScriptValue> stateObject) |
| { |
| if (!frame()) |
| return; |
| |
| // Per step 11 of section 6.5.9 (history traversal) of the HTML5 spec, we |
| // defer firing of popstate until we're in the complete state. |
| if (document()->isLoadCompleted()) |
| enqueuePopstateEvent(stateObject); |
| else |
| m_pendingStateObject = stateObject; |
| } |
| |
| LocalDOMWindow::~LocalDOMWindow() |
| { |
| ASSERT(m_hasBeenReset); |
| reset(); |
| |
| #if ENABLE(OILPAN) |
| // Oilpan: the frame host and document objects are |
| // also garbage collected; cannot notify these |
| // when removing event listeners. |
| removeAllEventListenersInternal(DoNotBroadcastListenerRemoval); |
| |
| // Cleared when detaching document. |
| ASSERT(!m_eventQueue); |
| #else |
| removeAllEventListenersInternal(DoBroadcastListenerRemoval); |
| |
| ASSERT(m_document->isStopped()); |
| clearDocument(); |
| #endif |
| } |
| |
| const AtomicString& LocalDOMWindow::interfaceName() const |
| { |
| return EventTargetNames::LocalDOMWindow; |
| } |
| |
| ExecutionContext* LocalDOMWindow::executionContext() const |
| { |
| return m_document.get(); |
| } |
| |
| LocalDOMWindow* LocalDOMWindow::toDOMWindow() |
| { |
| return this; |
| } |
| |
| PassRefPtrWillBeRawPtr<MediaQueryList> LocalDOMWindow::matchMedia(const String& media) |
| { |
| return document() ? document()->mediaQueryMatcher().matchMedia(media) : nullptr; |
| } |
| |
| Page* LocalDOMWindow::page() |
| { |
| return frame() ? frame()->page() : 0; |
| } |
| |
| void LocalDOMWindow::frameDestroyed() |
| { |
| FrameDestructionObserver::frameDestroyed(); |
| reset(); |
| } |
| |
| void LocalDOMWindow::willDetachFrameHost() |
| { |
| m_frame->host()->eventHandlerRegistry().didRemoveAllEventHandlers(*this); |
| InspectorInstrumentation::frameWindowDiscarded(m_frame, this); |
| } |
| |
| void LocalDOMWindow::willDestroyDocumentInFrame() |
| { |
| // It is necessary to copy m_properties to a separate vector because the DOMWindowProperties may |
| // unregister themselves from the LocalDOMWindow as a result of the call to willDestroyGlobalObjectInFrame. |
| Vector<DOMWindowProperty*> properties; |
| copyToVector(m_properties, properties); |
| for (size_t i = 0; i < properties.size(); ++i) |
| properties[i]->willDestroyGlobalObjectInFrame(); |
| } |
| |
| void LocalDOMWindow::willDetachDocumentFromFrame() |
| { |
| // It is necessary to copy m_properties to a separate vector because the DOMWindowProperties may |
| // unregister themselves from the LocalDOMWindow as a result of the call to willDetachGlobalObjectFromFrame. |
| Vector<DOMWindowProperty*> properties; |
| copyToVector(m_properties, properties); |
| for (size_t i = 0; i < properties.size(); ++i) |
| properties[i]->willDetachGlobalObjectFromFrame(); |
| } |
| |
| void LocalDOMWindow::registerProperty(DOMWindowProperty* property) |
| { |
| m_properties.add(property); |
| } |
| |
| void LocalDOMWindow::unregisterProperty(DOMWindowProperty* property) |
| { |
| m_properties.remove(property); |
| } |
| |
| void LocalDOMWindow::reset() |
| { |
| willDestroyDocumentInFrame(); |
| resetDOMWindowProperties(); |
| } |
| |
| void LocalDOMWindow::resetDOMWindowProperties() |
| { |
| m_properties.clear(); |
| |
| m_screen = nullptr; |
| m_history = nullptr; |
| m_locationbar = nullptr; |
| m_menubar = nullptr; |
| m_personalbar = nullptr; |
| m_scrollbars = nullptr; |
| m_statusbar = nullptr; |
| m_toolbar = nullptr; |
| m_console = nullptr; |
| m_navigator = nullptr; |
| m_performance = nullptr; |
| m_location = nullptr; |
| m_media = nullptr; |
| m_sessionStorage = nullptr; |
| m_localStorage = nullptr; |
| m_applicationCache = nullptr; |
| #if ENABLE(ASSERT) |
| m_hasBeenReset = true; |
| #endif |
| } |
| |
| bool LocalDOMWindow::isCurrentlyDisplayedInFrame() const |
| { |
| return m_frame && m_frame->domWindow() == this && m_frame->host(); |
| } |
| |
| int LocalDOMWindow::orientation() const |
| { |
| ASSERT(RuntimeEnabledFeatures::orientationEventEnabled()); |
| |
| if (!m_frame) |
| return 0; |
| |
| int orientation = screenOrientationAngle(m_frame->view()); |
| // For backward compatibility, we want to return a value in the range of |
| // [-90; 180] instead of [0; 360[ because window.orientation used to behave |
| // like that in WebKit (this is a WebKit proprietary API). |
| if (orientation == 270) |
| return -90; |
| return orientation; |
| } |
| |
| Screen& LocalDOMWindow::screen() const |
| { |
| if (!m_screen) |
| m_screen = Screen::create(m_frame); |
| return *m_screen; |
| } |
| |
| History& LocalDOMWindow::history() const |
| { |
| if (!m_history) |
| m_history = History::create(m_frame); |
| return *m_history; |
| } |
| |
| BarProp& LocalDOMWindow::locationbar() const |
| { |
| if (!m_locationbar) |
| m_locationbar = BarProp::create(m_frame, BarProp::Locationbar); |
| return *m_locationbar; |
| } |
| |
| BarProp& LocalDOMWindow::menubar() const |
| { |
| if (!m_menubar) |
| m_menubar = BarProp::create(m_frame, BarProp::Menubar); |
| return *m_menubar; |
| } |
| |
| BarProp& LocalDOMWindow::personalbar() const |
| { |
| if (!m_personalbar) |
| m_personalbar = BarProp::create(m_frame, BarProp::Personalbar); |
| return *m_personalbar; |
| } |
| |
| BarProp& LocalDOMWindow::scrollbars() const |
| { |
| if (!m_scrollbars) |
| m_scrollbars = BarProp::create(m_frame, BarProp::Scrollbars); |
| return *m_scrollbars; |
| } |
| |
| BarProp& LocalDOMWindow::statusbar() const |
| { |
| if (!m_statusbar) |
| m_statusbar = BarProp::create(m_frame, BarProp::Statusbar); |
| return *m_statusbar; |
| } |
| |
| BarProp& LocalDOMWindow::toolbar() const |
| { |
| if (!m_toolbar) |
| m_toolbar = BarProp::create(m_frame, BarProp::Toolbar); |
| return *m_toolbar; |
| } |
| |
| Console& LocalDOMWindow::console() const |
| { |
| if (!m_console) |
| m_console = Console::create(m_frame); |
| return *m_console; |
| } |
| |
| FrameConsole* LocalDOMWindow::frameConsole() const |
| { |
| if (!isCurrentlyDisplayedInFrame()) |
| return 0; |
| return &m_frame->console(); |
| } |
| |
| ApplicationCache* LocalDOMWindow::applicationCache() const |
| { |
| if (!isCurrentlyDisplayedInFrame()) |
| return 0; |
| if (!m_applicationCache) |
| m_applicationCache = ApplicationCache::create(m_frame); |
| return m_applicationCache.get(); |
| } |
| |
| Navigator& LocalDOMWindow::navigator() const |
| { |
| if (!m_navigator) |
| m_navigator = Navigator::create(m_frame); |
| return *m_navigator; |
| } |
| |
| Performance& LocalDOMWindow::performance() const |
| { |
| if (!m_performance) |
| m_performance = Performance::create(m_frame); |
| return *m_performance; |
| } |
| |
| Location& LocalDOMWindow::location() const |
| { |
| if (!m_location) |
| m_location = Location::create(m_frame); |
| return *m_location; |
| } |
| |
| Storage* LocalDOMWindow::sessionStorage(ExceptionState& exceptionState) const |
| { |
| if (!isCurrentlyDisplayedInFrame()) |
| return 0; |
| |
| Document* document = this->document(); |
| if (!document) |
| return 0; |
| |
| String accessDeniedMessage = "Access is denied for this document."; |
| if (!document->securityOrigin()->canAccessLocalStorage()) { |
| if (document->isSandboxed(SandboxOrigin)) |
| exceptionState.throwSecurityError("The document is sandboxed and lacks the 'allow-same-origin' flag."); |
| else if (document->url().protocolIs("data")) |
| exceptionState.throwSecurityError("Storage is disabled inside 'data:' URLs."); |
| else |
| exceptionState.throwSecurityError(accessDeniedMessage); |
| return 0; |
| } |
| |
| if (m_sessionStorage) { |
| if (!m_sessionStorage->area()->canAccessStorage(m_frame)) { |
| exceptionState.throwSecurityError(accessDeniedMessage); |
| return 0; |
| } |
| return m_sessionStorage.get(); |
| } |
| |
| Page* page = document->page(); |
| if (!page) |
| return 0; |
| |
| OwnPtrWillBeRawPtr<StorageArea> storageArea = page->sessionStorage()->storageArea(document->securityOrigin()); |
| if (!storageArea->canAccessStorage(m_frame)) { |
| exceptionState.throwSecurityError(accessDeniedMessage); |
| return 0; |
| } |
| |
| m_sessionStorage = Storage::create(m_frame, storageArea.release()); |
| return m_sessionStorage.get(); |
| } |
| |
| Storage* LocalDOMWindow::localStorage(ExceptionState& exceptionState) const |
| { |
| if (!isCurrentlyDisplayedInFrame()) |
| return 0; |
| |
| Document* document = this->document(); |
| if (!document) |
| return 0; |
| |
| String accessDeniedMessage = "Access is denied for this document."; |
| if (!document->securityOrigin()->canAccessLocalStorage()) { |
| if (document->isSandboxed(SandboxOrigin)) |
| exceptionState.throwSecurityError("The document is sandboxed and lacks the 'allow-same-origin' flag."); |
| else if (document->url().protocolIs("data")) |
| exceptionState.throwSecurityError("Storage is disabled inside 'data:' URLs."); |
| else |
| exceptionState.throwSecurityError(accessDeniedMessage); |
| return 0; |
| } |
| |
| if (m_localStorage) { |
| if (!m_localStorage->area()->canAccessStorage(m_frame)) { |
| exceptionState.throwSecurityError(accessDeniedMessage); |
| return 0; |
| } |
| return m_localStorage.get(); |
| } |
| |
| // FIXME: Seems this check should be much higher? |
| FrameHost* host = document->frameHost(); |
| if (!host || !host->settings().localStorageEnabled()) |
| return 0; |
| |
| OwnPtrWillBeRawPtr<StorageArea> storageArea = StorageNamespace::localStorageArea(document->securityOrigin()); |
| if (!storageArea->canAccessStorage(m_frame)) { |
| exceptionState.throwSecurityError(accessDeniedMessage); |
| return 0; |
| } |
| |
| m_localStorage = Storage::create(m_frame, storageArea.release()); |
| return m_localStorage.get(); |
| } |
| |
| void LocalDOMWindow::postMessage(PassRefPtr<SerializedScriptValue> message, const MessagePortArray* ports, const String& targetOrigin, LocalDOMWindow* source, ExceptionState& exceptionState) |
| { |
| if (!isCurrentlyDisplayedInFrame()) |
| return; |
| |
| Document* sourceDocument = source->document(); |
| |
| // Compute the target origin. We need to do this synchronously in order |
| // to generate the SyntaxError exception correctly. |
| RefPtr<SecurityOrigin> target; |
| if (targetOrigin == "/") { |
| if (!sourceDocument) |
| return; |
| target = sourceDocument->securityOrigin(); |
| } else if (targetOrigin != "*") { |
| target = SecurityOrigin::createFromString(targetOrigin); |
| // It doesn't make sense target a postMessage at a unique origin |
| // because there's no way to represent a unique origin in a string. |
| if (target->isUnique()) { |
| exceptionState.throwDOMException(SyntaxError, "Invalid target origin '" + targetOrigin + "' in a call to 'postMessage'."); |
| return; |
| } |
| } |
| |
| OwnPtr<MessagePortChannelArray> channels = MessagePort::disentanglePorts(ports, exceptionState); |
| if (exceptionState.hadException()) |
| return; |
| |
| // Capture the source of the message. We need to do this synchronously |
| // in order to capture the source of the message correctly. |
| if (!sourceDocument) |
| return; |
| String sourceOrigin = sourceDocument->securityOrigin()->toString(); |
| |
| if (MixedContentChecker::isMixedContent(sourceDocument->securityOrigin(), document()->url())) |
| UseCounter::count(document(), UseCounter::PostMessageFromSecureToInsecure); |
| else if (MixedContentChecker::isMixedContent(document()->securityOrigin(), sourceDocument->url())) |
| UseCounter::count(document(), UseCounter::PostMessageFromInsecureToSecure); |
| |
| // Capture stack trace only when inspector front-end is loaded as it may be time consuming. |
| RefPtrWillBeRawPtr<ScriptCallStack> stackTrace = nullptr; |
| if (InspectorInstrumentation::consoleAgentEnabled(sourceDocument)) |
| stackTrace = createScriptCallStack(ScriptCallStack::maxCallStackSizeToCapture, true); |
| |
| // Schedule the message. |
| OwnPtr<PostMessageTimer> timer = adoptPtr(new PostMessageTimer(*this, message, sourceOrigin, source, channels.release(), target.get(), stackTrace.release(), UserGestureIndicator::currentToken())); |
| timer->startOneShot(0, FROM_HERE); |
| timer->suspendIfNeeded(); |
| m_postMessageTimers.add(timer.release()); |
| } |
| |
| void LocalDOMWindow::postMessageTimerFired(PostMessageTimer* timer) |
| { |
| if (!isCurrentlyDisplayedInFrame()) { |
| m_postMessageTimers.remove(timer); |
| return; |
| } |
| |
| RefPtrWillBeRawPtr<MessageEvent> event = timer->event(); |
| |
| // Give the embedder a chance to intercept this postMessage because this |
| // LocalDOMWindow might be a proxy for another in browsers that support |
| // postMessage calls across WebKit instances. |
| if (m_frame->loader().client()->willCheckAndDispatchMessageEvent(timer->targetOrigin(), event.get())) { |
| m_postMessageTimers.remove(timer); |
| return; |
| } |
| |
| UserGestureIndicator gestureIndicator(timer->userGestureToken()); |
| |
| event->entangleMessagePorts(document()); |
| dispatchMessageEventWithOriginCheck(timer->targetOrigin(), event, timer->stackTrace()); |
| m_postMessageTimers.remove(timer); |
| } |
| |
| void LocalDOMWindow::dispatchMessageEventWithOriginCheck(SecurityOrigin* intendedTargetOrigin, PassRefPtrWillBeRawPtr<Event> event, PassRefPtrWillBeRawPtr<ScriptCallStack> stackTrace) |
| { |
| if (intendedTargetOrigin) { |
| // Check target origin now since the target document may have changed since the timer was scheduled. |
| if (!intendedTargetOrigin->isSameSchemeHostPort(document()->securityOrigin())) { |
| String message = ExceptionMessages::failedToExecute("postMessage", "DOMWindow", "The target origin provided ('" + intendedTargetOrigin->toString() + "') does not match the recipient window's origin ('" + document()->securityOrigin()->toString() + "')."); |
| RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, message); |
| consoleMessage->setCallStack(stackTrace); |
| frameConsole()->addMessage(consoleMessage.release()); |
| return; |
| } |
| } |
| |
| dispatchEvent(event); |
| } |
| |
| DOMSelection* LocalDOMWindow::getSelection() |
| { |
| if (!isCurrentlyDisplayedInFrame() || !m_frame) |
| return 0; |
| |
| return m_frame->document()->getSelection(); |
| } |
| |
| Element* LocalDOMWindow::frameElement() const |
| { |
| if (!m_frame) |
| return 0; |
| |
| // The bindings security check should ensure we're same origin... |
| ASSERT(!m_frame->owner() || m_frame->owner()->isLocal()); |
| return m_frame->deprecatedLocalOwner(); |
| } |
| |
| void LocalDOMWindow::focus(ExecutionContext* context) |
| { |
| if (!m_frame) |
| return; |
| |
| FrameHost* host = m_frame->host(); |
| if (!host) |
| return; |
| |
| bool allowFocus = WindowFocusAllowedIndicator::windowFocusAllowed(); |
| if (context) { |
| ASSERT(isMainThread()); |
| Document* activeDocument = toDocument(context); |
| if (opener() && opener() != this && activeDocument->domWindow() == opener()) |
| allowFocus = true; |
| } |
| |
| // If we're a top level window, bring the window to the front. |
| if (m_frame->isMainFrame() && allowFocus) |
| host->chrome().focus(); |
| |
| if (!m_frame) |
| return; |
| |
| m_frame->eventHandler().focusDocumentView(); |
| } |
| |
| void LocalDOMWindow::blur() |
| { |
| } |
| |
| void LocalDOMWindow::close(ExecutionContext* context) |
| { |
| if (!m_frame || !m_frame->isMainFrame()) |
| return; |
| |
| Page* page = m_frame->page(); |
| if (!page) |
| return; |
| |
| if (context) { |
| ASSERT(isMainThread()); |
| Document* activeDocument = toDocument(context); |
| if (!activeDocument) |
| return; |
| |
| if (!activeDocument->canNavigate(*m_frame)) |
| return; |
| } |
| |
| Settings* settings = m_frame->settings(); |
| bool allowScriptsToCloseWindows = settings && settings->allowScriptsToCloseWindows(); |
| |
| if (!(page->openedByDOM() || page->backForward().backForwardListCount() <= 1 || allowScriptsToCloseWindows)) { |
| frameConsole()->addMessage(ConsoleMessage::create(JSMessageSource, WarningMessageLevel, "Scripts may close only the windows that were opened by it.")); |
| return; |
| } |
| |
| if (!m_frame->loader().shouldClose()) |
| return; |
| |
| InspectorInstrumentation::willCloseWindow(context); |
| |
| page->chrome().closeWindowSoon(); |
| } |
| |
| void LocalDOMWindow::print() |
| { |
| if (!m_frame) |
| return; |
| |
| FrameHost* host = m_frame->host(); |
| if (!host) |
| return; |
| |
| if (m_frame->loader().state() != FrameStateComplete) { |
| m_shouldPrintWhenFinishedLoading = true; |
| return; |
| } |
| m_shouldPrintWhenFinishedLoading = false; |
| host->chrome().print(m_frame); |
| } |
| |
| void LocalDOMWindow::stop() |
| { |
| if (!m_frame) |
| return; |
| m_frame->loader().stopAllLoaders(); |
| } |
| |
| void LocalDOMWindow::alert(const String& message) |
| { |
| if (!m_frame) |
| return; |
| |
| m_frame->document()->updateRenderTreeIfNeeded(); |
| |
| FrameHost* host = m_frame->host(); |
| if (!host) |
| return; |
| |
| host->chrome().runJavaScriptAlert(m_frame, message); |
| } |
| |
| bool LocalDOMWindow::confirm(const String& message) |
| { |
| if (!m_frame) |
| return false; |
| |
| m_frame->document()->updateRenderTreeIfNeeded(); |
| |
| FrameHost* host = m_frame->host(); |
| if (!host) |
| return false; |
| |
| return host->chrome().runJavaScriptConfirm(m_frame, message); |
| } |
| |
| String LocalDOMWindow::prompt(const String& message, const String& defaultValue) |
| { |
| if (!m_frame) |
| return String(); |
| |
| m_frame->document()->updateRenderTreeIfNeeded(); |
| |
| FrameHost* host = m_frame->host(); |
| if (!host) |
| return String(); |
| |
| String returnValue; |
| if (host->chrome().runJavaScriptPrompt(m_frame, message, defaultValue, returnValue)) |
| return returnValue; |
| |
| return String(); |
| } |
| |
| bool LocalDOMWindow::find(const String& string, bool caseSensitive, bool backwards, bool wrap, bool /*wholeWord*/, bool /*searchInFrames*/, bool /*showDialog*/) const |
| { |
| if (!isCurrentlyDisplayedInFrame()) |
| return false; |
| |
| // |m_frame| can be destructed during |Editor::findString()| via |
| // |Document::updateLayou()|, e.g. event handler removes a frame. |
| RefPtr<LocalFrame> protectFrame(m_frame); |
| |
| // FIXME (13016): Support wholeWord, searchInFrames and showDialog |
| return m_frame->editor().findString(string, !backwards, caseSensitive, wrap, false); |
| } |
| |
| bool LocalDOMWindow::offscreenBuffering() const |
| { |
| return true; |
| } |
| |
| int LocalDOMWindow::outerHeight() const |
| { |
| if (!m_frame) |
| return 0; |
| |
| FrameHost* host = m_frame->host(); |
| if (!host) |
| return 0; |
| |
| if (host->settings().reportScreenSizeInPhysicalPixelsQuirk()) |
| return lroundf(host->chrome().windowRect().height() * host->deviceScaleFactor()); |
| return static_cast<int>(host->chrome().windowRect().height()); |
| } |
| |
| int LocalDOMWindow::outerWidth() const |
| { |
| if (!m_frame) |
| return 0; |
| |
| FrameHost* host = m_frame->host(); |
| if (!host) |
| return 0; |
| |
| if (host->settings().reportScreenSizeInPhysicalPixelsQuirk()) |
| return lroundf(host->chrome().windowRect().width() * host->deviceScaleFactor()); |
| return static_cast<int>(host->chrome().windowRect().width()); |
| } |
| |
| int LocalDOMWindow::innerHeight() const |
| { |
| if (!m_frame) |
| return 0; |
| |
| FrameView* view = m_frame->view(); |
| if (!view) |
| return 0; |
| |
| // FIXME: This is potentially too much work. We really only need to know the dimensions of the parent frame's renderer. |
| if (Frame* parent = m_frame->tree().parent()) { |
| if (parent && parent->isLocalFrame()) |
| toLocalFrame(parent)->document()->updateLayoutIgnorePendingStylesheets(); |
| } |
| |
| return adjustForAbsoluteZoom(view->visibleContentRect(IncludeScrollbars).height(), m_frame->pageZoomFactor()); |
| } |
| |
| int LocalDOMWindow::innerWidth() const |
| { |
| if (!m_frame) |
| return 0; |
| |
| FrameView* view = m_frame->view(); |
| if (!view) |
| return 0; |
| |
| // FIXME: This is potentially too much work. We really only need to know the dimensions of the parent frame's renderer. |
| if (Frame* parent = m_frame->tree().parent()) { |
| if (parent && parent->isLocalFrame()) |
| toLocalFrame(parent)->document()->updateLayoutIgnorePendingStylesheets(); |
| } |
| |
| return adjustForAbsoluteZoom(view->visibleContentRect(IncludeScrollbars).width(), m_frame->pageZoomFactor()); |
| } |
| |
| int LocalDOMWindow::screenX() const |
| { |
| if (!m_frame) |
| return 0; |
| |
| FrameHost* host = m_frame->host(); |
| if (!host) |
| return 0; |
| |
| if (host->settings().reportScreenSizeInPhysicalPixelsQuirk()) |
| return lroundf(host->chrome().windowRect().x() * host->deviceScaleFactor()); |
| return static_cast<int>(host->chrome().windowRect().x()); |
| } |
| |
| int LocalDOMWindow::screenY() const |
| { |
| if (!m_frame) |
| return 0; |
| |
| FrameHost* host = m_frame->host(); |
| if (!host) |
| return 0; |
| |
| if (host->settings().reportScreenSizeInPhysicalPixelsQuirk()) |
| return lroundf(host->chrome().windowRect().y() * host->deviceScaleFactor()); |
| return static_cast<int>(host->chrome().windowRect().y()); |
| } |
| |
| int LocalDOMWindow::scrollX() const |
| { |
| if (!m_frame) |
| return 0; |
| |
| FrameView* view = m_frame->view(); |
| if (!view) |
| return 0; |
| |
| m_frame->document()->updateLayoutIgnorePendingStylesheets(); |
| |
| return adjustForAbsoluteZoom(view->scrollX(), m_frame->pageZoomFactor()); |
| } |
| |
| int LocalDOMWindow::scrollY() const |
| { |
| if (!m_frame) |
| return 0; |
| |
| FrameView* view = m_frame->view(); |
| if (!view) |
| return 0; |
| |
| m_frame->document()->updateLayoutIgnorePendingStylesheets(); |
| |
| return adjustForAbsoluteZoom(view->scrollY(), m_frame->pageZoomFactor()); |
| } |
| |
| bool LocalDOMWindow::closed() const |
| { |
| return !m_frame; |
| } |
| |
| unsigned LocalDOMWindow::length() const |
| { |
| if (!isCurrentlyDisplayedInFrame()) |
| return 0; |
| |
| return m_frame->tree().scopedChildCount(); |
| } |
| |
| const AtomicString& LocalDOMWindow::name() const |
| { |
| if (!isCurrentlyDisplayedInFrame()) |
| return nullAtom; |
| |
| return m_frame->tree().name(); |
| } |
| |
| void LocalDOMWindow::setName(const AtomicString& name) |
| { |
| if (!isCurrentlyDisplayedInFrame()) |
| return; |
| |
| m_frame->tree().setName(name); |
| ASSERT(m_frame->loader().client()); |
| m_frame->loader().client()->didChangeName(name); |
| } |
| |
| void LocalDOMWindow::setStatus(const String& string) |
| { |
| m_status = string; |
| |
| if (!m_frame) |
| return; |
| |
| FrameHost* host = m_frame->host(); |
| if (!host) |
| return; |
| |
| ASSERT(m_frame->document()); // Client calls shouldn't be made when the frame is in inconsistent state. |
| host->chrome().setStatusbarText(m_frame, m_status); |
| } |
| |
| void LocalDOMWindow::setDefaultStatus(const String& string) |
| { |
| m_defaultStatus = string; |
| |
| if (!m_frame) |
| return; |
| |
| FrameHost* host = m_frame->host(); |
| if (!host) |
| return; |
| |
| ASSERT(m_frame->document()); // Client calls shouldn't be made when the frame is in inconsistent state. |
| host->chrome().setStatusbarText(m_frame, m_defaultStatus); |
| } |
| |
| LocalDOMWindow* LocalDOMWindow::self() const |
| { |
| if (!m_frame) |
| return 0; |
| |
| return m_frame->domWindow(); |
| } |
| |
| LocalDOMWindow* LocalDOMWindow::opener() const |
| { |
| if (!m_frame) |
| return 0; |
| |
| LocalFrame* opener = m_frame->loader().opener(); |
| if (!opener) |
| return 0; |
| |
| return opener->domWindow(); |
| } |
| |
| LocalDOMWindow* LocalDOMWindow::parent() const |
| { |
| if (!m_frame) |
| return 0; |
| |
| Frame* parent = m_frame->tree().parent(); |
| if (parent) |
| return parent->domWindow(); |
| |
| return m_frame->domWindow(); |
| } |
| |
| LocalDOMWindow* LocalDOMWindow::top() const |
| { |
| if (!m_frame) |
| return 0; |
| |
| return m_frame->tree().top()->domWindow(); |
| } |
| |
| Document* LocalDOMWindow::document() const |
| { |
| return m_document.get(); |
| } |
| |
| StyleMedia& LocalDOMWindow::styleMedia() const |
| { |
| if (!m_media) |
| m_media = StyleMedia::create(m_frame); |
| return *m_media; |
| } |
| |
| PassRefPtrWillBeRawPtr<CSSStyleDeclaration> LocalDOMWindow::getComputedStyle(Element* elt, const String& pseudoElt) const |
| { |
| if (!elt) |
| return nullptr; |
| |
| return CSSComputedStyleDeclaration::create(elt, false, pseudoElt); |
| } |
| |
| PassRefPtrWillBeRawPtr<CSSRuleList> LocalDOMWindow::getMatchedCSSRules(Element* element, const String& pseudoElement) const |
| { |
| if (!element) |
| return nullptr; |
| |
| if (!isCurrentlyDisplayedInFrame()) |
| return nullptr; |
| |
| unsigned colonStart = pseudoElement[0] == ':' ? (pseudoElement[1] == ':' ? 2 : 1) : 0; |
| CSSSelector::PseudoType pseudoType = CSSSelector::parsePseudoType(AtomicString(pseudoElement.substring(colonStart))); |
| if (pseudoType == CSSSelector::PseudoUnknown && !pseudoElement.isEmpty()) |
| return nullptr; |
| |
| unsigned rulesToInclude = StyleResolver::AuthorCSSRules; |
| PseudoId pseudoId = CSSSelector::pseudoId(pseudoType); |
| return m_frame->document()->ensureStyleResolver().pseudoCSSRulesForElement(element, pseudoId, rulesToInclude); |
| } |
| |
| PassRefPtrWillBeRawPtr<WebKitPoint> LocalDOMWindow::webkitConvertPointFromNodeToPage(Node* node, const WebKitPoint* p) const |
| { |
| if (!node || !p) |
| return nullptr; |
| |
| if (!document()) |
| return nullptr; |
| |
| document()->updateLayoutIgnorePendingStylesheets(); |
| |
| FloatPoint pagePoint(p->x(), p->y()); |
| pagePoint = node->convertToPage(pagePoint); |
| return WebKitPoint::create(pagePoint.x(), pagePoint.y()); |
| } |
| |
| PassRefPtrWillBeRawPtr<WebKitPoint> LocalDOMWindow::webkitConvertPointFromPageToNode(Node* node, const WebKitPoint* p) const |
| { |
| if (!node || !p) |
| return nullptr; |
| |
| if (!document()) |
| return nullptr; |
| |
| document()->updateLayoutIgnorePendingStylesheets(); |
| |
| FloatPoint nodePoint(p->x(), p->y()); |
| nodePoint = node->convertFromPage(nodePoint); |
| return WebKitPoint::create(nodePoint.x(), nodePoint.y()); |
| } |
| |
| double LocalDOMWindow::devicePixelRatio() const |
| { |
| if (!m_frame) |
| return 0.0; |
| |
| return m_frame->devicePixelRatio(); |
| } |
| |
| static bool scrollBehaviorFromScrollOptions(const Dictionary& scrollOptions, ScrollBehavior& scrollBehavior, ExceptionState& exceptionState) |
| { |
| String scrollBehaviorString; |
| if (!DictionaryHelper::get(scrollOptions, "behavior", scrollBehaviorString)) { |
| scrollBehavior = ScrollBehaviorAuto; |
| return true; |
| } |
| |
| if (ScrollableArea::scrollBehaviorFromString(scrollBehaviorString, scrollBehavior)) |
| return true; |
| |
| exceptionState.throwTypeError("The ScrollBehavior provided is invalid."); |
| return false; |
| } |
| |
| void LocalDOMWindow::scrollBy(int x, int y, ScrollBehavior scrollBehavior) const |
| { |
| if (!isCurrentlyDisplayedInFrame()) |
| return; |
| |
| document()->updateLayoutIgnorePendingStylesheets(); |
| |
| FrameView* view = m_frame->view(); |
| if (!view) |
| return; |
| |
| IntSize scaledOffset(x * m_frame->pageZoomFactor(), y * m_frame->pageZoomFactor()); |
| view->scrollBy(scaledOffset, scrollBehavior); |
| } |
| |
| void LocalDOMWindow::scrollBy(int x, int y, const Dictionary& scrollOptions, ExceptionState &exceptionState) const |
| { |
| ScrollBehavior scrollBehavior = ScrollBehaviorAuto; |
| if (!scrollBehaviorFromScrollOptions(scrollOptions, scrollBehavior, exceptionState)) |
| return; |
| scrollBy(x, y, scrollBehavior); |
| } |
| |
| void LocalDOMWindow::scrollTo(int x, int y, ScrollBehavior scrollBehavior) const |
| { |
| if (!isCurrentlyDisplayedInFrame()) |
| return; |
| |
| document()->updateLayoutIgnorePendingStylesheets(); |
| |
| RefPtr<FrameView> view = m_frame->view(); |
| if (!view) |
| return; |
| |
| IntPoint layoutPos(x * m_frame->pageZoomFactor(), y * m_frame->pageZoomFactor()); |
| view->setScrollPosition(layoutPos, scrollBehavior); |
| } |
| |
| void LocalDOMWindow::scrollTo(int x, int y, const Dictionary& scrollOptions, ExceptionState& exceptionState) const |
| { |
| ScrollBehavior scrollBehavior = ScrollBehaviorAuto; |
| if (!scrollBehaviorFromScrollOptions(scrollOptions, scrollBehavior, exceptionState)) |
| return; |
| scrollTo(x, y, scrollBehavior); |
| } |
| |
| void LocalDOMWindow::moveBy(float x, float y) const |
| { |
| if (!m_frame || !m_frame->isMainFrame()) |
| return; |
| |
| FrameHost* host = m_frame->host(); |
| if (!host) |
| return; |
| |
| FloatRect windowRect = host->chrome().windowRect(); |
| windowRect.move(x, y); |
| // Security check (the spec talks about UniversalBrowserWrite to disable this check...) |
| host->chrome().setWindowRect(adjustWindowRect(*m_frame, windowRect)); |
| } |
| |
| void LocalDOMWindow::moveTo(float x, float y) const |
| { |
| if (!m_frame || !m_frame->isMainFrame()) |
| return; |
| |
| FrameHost* host = m_frame->host(); |
| if (!host) |
| return; |
| |
| FloatRect windowRect = host->chrome().windowRect(); |
| windowRect.setLocation(FloatPoint(x, y)); |
| // Security check (the spec talks about UniversalBrowserWrite to disable this check...) |
| host->chrome().setWindowRect(adjustWindowRect(*m_frame, windowRect)); |
| } |
| |
| void LocalDOMWindow::resizeBy(float x, float y) const |
| { |
| if (!m_frame || !m_frame->isMainFrame()) |
| return; |
| |
| FrameHost* host = m_frame->host(); |
| if (!host) |
| return; |
| |
| FloatRect fr = host->chrome().windowRect(); |
| FloatSize dest = fr.size() + FloatSize(x, y); |
| FloatRect update(fr.location(), dest); |
| host->chrome().setWindowRect(adjustWindowRect(*m_frame, update)); |
| } |
| |
| void LocalDOMWindow::resizeTo(float width, float height) const |
| { |
| if (!m_frame || !m_frame->isMainFrame()) |
| return; |
| |
| FrameHost* host = m_frame->host(); |
| if (!host) |
| return; |
| |
| FloatRect fr = host->chrome().windowRect(); |
| FloatSize dest = FloatSize(width, height); |
| FloatRect update(fr.location(), dest); |
| host->chrome().setWindowRect(adjustWindowRect(*m_frame, update)); |
| } |
| |
| int LocalDOMWindow::requestAnimationFrame(PassOwnPtr<RequestAnimationFrameCallback> callback) |
| { |
| callback->m_useLegacyTimeBase = false; |
| if (Document* d = document()) |
| return d->requestAnimationFrame(callback); |
| return 0; |
| } |
| |
| int LocalDOMWindow::webkitRequestAnimationFrame(PassOwnPtr<RequestAnimationFrameCallback> callback) |
| { |
| callback->m_useLegacyTimeBase = true; |
| if (Document* d = document()) |
| return d->requestAnimationFrame(callback); |
| return 0; |
| } |
| |
| void LocalDOMWindow::cancelAnimationFrame(int id) |
| { |
| if (Document* d = document()) |
| d->cancelAnimationFrame(id); |
| } |
| |
| DOMWindowCSS& LocalDOMWindow::css() const |
| { |
| if (!m_css) |
| m_css = DOMWindowCSS::create(); |
| return *m_css; |
| } |
| |
| static void didAddStorageEventListener(LocalDOMWindow* window) |
| { |
| // Creating these blink::Storage objects informs the system that we'd like to receive |
| // notifications about storage events that might be triggered in other processes. Rather |
| // than subscribe to these notifications explicitly, we subscribe to them implicitly to |
| // simplify the work done by the system. |
| window->localStorage(IGNORE_EXCEPTION); |
| window->sessionStorage(IGNORE_EXCEPTION); |
| } |
| |
| bool LocalDOMWindow::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture) |
| { |
| if (!EventTarget::addEventListener(eventType, listener, useCapture)) |
| return false; |
| |
| if (m_frame && m_frame->host()) |
| m_frame->host()->eventHandlerRegistry().didAddEventHandler(*this, eventType); |
| |
| if (Document* document = this->document()) { |
| document->addListenerTypeIfNeeded(eventType); |
| if (eventType == EventTypeNames::storage) |
| didAddStorageEventListener(this); |
| } |
| |
| lifecycleNotifier().notifyAddEventListener(this, eventType); |
| |
| if (eventType == EventTypeNames::unload) { |
| UseCounter::count(document(), UseCounter::DocumentUnloadRegistered); |
| addUnloadEventListener(this); |
| } else if (eventType == EventTypeNames::beforeunload) { |
| UseCounter::count(document(), UseCounter::DocumentBeforeUnloadRegistered); |
| if (allowsBeforeUnloadListeners(this)) { |
| // This is confusingly named. It doesn't actually add the listener. It just increments a count |
| // so that we know we have listeners registered for the purposes of determining if we can |
| // fast terminate the renderer process. |
| addBeforeUnloadEventListener(this); |
| } else { |
| // Subframes return false from allowsBeforeUnloadListeners. |
| UseCounter::count(document(), UseCounter::SubFrameBeforeUnloadRegistered); |
| } |
| } |
| |
| return true; |
| } |
| |
| bool LocalDOMWindow::removeEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture) |
| { |
| if (!EventTarget::removeEventListener(eventType, listener, useCapture)) |
| return false; |
| |
| if (m_frame && m_frame->host()) |
| m_frame->host()->eventHandlerRegistry().didRemoveEventHandler(*this, eventType); |
| |
| lifecycleNotifier().notifyRemoveEventListener(this, eventType); |
| |
| if (eventType == EventTypeNames::unload) { |
| removeUnloadEventListener(this); |
| } else if (eventType == EventTypeNames::beforeunload && allowsBeforeUnloadListeners(this)) { |
| removeBeforeUnloadEventListener(this); |
| } |
| |
| return true; |
| } |
| |
| void LocalDOMWindow::dispatchLoadEvent() |
| { |
| RefPtrWillBeRawPtr<Event> loadEvent(Event::create(EventTypeNames::load)); |
| if (m_frame && m_frame->loader().documentLoader() && !m_frame->loader().documentLoader()->timing()->loadEventStart()) { |
| // The DocumentLoader (and thus its DocumentLoadTiming) might get destroyed while dispatching |
| // the event, so protect it to prevent writing the end time into freed memory. |
| RefPtr<DocumentLoader> documentLoader = m_frame->loader().documentLoader(); |
| DocumentLoadTiming* timing = documentLoader->timing(); |
| timing->markLoadEventStart(); |
| dispatchEvent(loadEvent, document()); |
| timing->markLoadEventEnd(); |
| } else |
| dispatchEvent(loadEvent, document()); |
| |
| // For load events, send a separate load event to the enclosing frame only. |
| // This is a DOM extension and is independent of bubbling/capturing rules of |
| // the DOM. |
| FrameOwner* owner = m_frame ? m_frame->owner() : 0; |
| if (owner) |
| owner->dispatchLoad(); |
| |
| TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "MarkLoad", "data", InspectorMarkLoadEvent::data(frame())); |
| // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing. |
| InspectorInstrumentation::loadEventFired(frame()); |
| } |
| |
| bool LocalDOMWindow::dispatchEvent(PassRefPtrWillBeRawPtr<Event> prpEvent, PassRefPtrWillBeRawPtr<EventTarget> prpTarget) |
| { |
| ASSERT(!EventDispatchForbiddenScope::isEventDispatchForbidden()); |
| |
| RefPtrWillBeRawPtr<EventTarget> protect(this); |
| RefPtrWillBeRawPtr<Event> event = prpEvent; |
| |
| event->setTarget(prpTarget ? prpTarget : this); |
| event->setCurrentTarget(this); |
| event->setEventPhase(Event::AT_TARGET); |
| |
| TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "EventDispatch", "data", InspectorEventDispatchEvent::data(*event)); |
| // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing. |
| InspectorInstrumentationCookie cookie = InspectorInstrumentation::willDispatchEventOnWindow(frame(), *event, this); |
| |
| bool result = fireEventListeners(event.get()); |
| |
| InspectorInstrumentation::didDispatchEventOnWindow(cookie); |
| |
| return result; |
| } |
| |
| void LocalDOMWindow::removeAllEventListenersInternal(BroadcastListenerRemoval mode) |
| { |
| EventTarget::removeAllEventListeners(); |
| |
| lifecycleNotifier().notifyRemoveAllEventListeners(this); |
| |
| if (mode == DoBroadcastListenerRemoval) { |
| if (m_frame && m_frame->host()) |
| m_frame->host()->eventHandlerRegistry().didRemoveAllEventHandlers(*this); |
| } |
| |
| removeAllUnloadEventListeners(this); |
| removeAllBeforeUnloadEventListeners(this); |
| } |
| |
| void LocalDOMWindow::removeAllEventListeners() |
| { |
| removeAllEventListenersInternal(DoBroadcastListenerRemoval); |
| } |
| |
| void LocalDOMWindow::finishedLoading() |
| { |
| if (m_shouldPrintWhenFinishedLoading) { |
| m_shouldPrintWhenFinishedLoading = false; |
| print(); |
| } |
| } |
| |
| void LocalDOMWindow::setLocation(const String& urlString, LocalDOMWindow* callingWindow, LocalDOMWindow* enteredWindow, SetLocationLocking locking) |
| { |
| if (!isCurrentlyDisplayedInFrame()) |
| return; |
| |
| Document* activeDocument = callingWindow->document(); |
| if (!activeDocument) |
| return; |
| |
| ASSERT(m_frame); |
| if (!activeDocument->canNavigate(*m_frame)) |
| return; |
| |
| LocalFrame* firstFrame = enteredWindow->frame(); |
| if (!firstFrame) |
| return; |
| |
| KURL completedURL = firstFrame->document()->completeURL(urlString); |
| if (completedURL.isNull()) |
| return; |
| |
| if (isInsecureScriptAccess(*callingWindow, completedURL)) |
| return; |
| |
| V8DOMActivityLogger* activityLogger = V8DOMActivityLogger::currentActivityLoggerIfIsolatedWorld(); |
| if (activityLogger) { |
| Vector<String> argv; |
| argv.append("LocalDOMWindow"); |
| argv.append("url"); |
| argv.append(firstFrame->document()->url()); |
| argv.append(completedURL); |
| activityLogger->logEvent("blinkSetAttribute", argv.size(), argv.data()); |
| } |
| |
| // We want a new history item if we are processing a user gesture. |
| m_frame->navigationScheduler().scheduleLocationChange(activeDocument, |
| // FIXME: What if activeDocument()->frame() is 0? |
| completedURL, Referrer(activeDocument->outgoingReferrer(), activeDocument->referrerPolicy()), |
| locking != LockHistoryBasedOnGestureState); |
| } |
| |
| void LocalDOMWindow::printErrorMessage(const String& message) |
| { |
| if (!isCurrentlyDisplayedInFrame()) |
| return; |
| |
| if (message.isEmpty()) |
| return; |
| |
| frameConsole()->addMessage(ConsoleMessage::create(JSMessageSource, ErrorMessageLevel, message)); |
| } |
| |
| // FIXME: Once we're throwing exceptions for cross-origin access violations, we will always sanitize the target |
| // frame details, so we can safely combine 'crossDomainAccessErrorMessage' with this method after considering |
| // exactly which details may be exposed to JavaScript. |
| // |
| // http://crbug.com/17325 |
| String LocalDOMWindow::sanitizedCrossDomainAccessErrorMessage(LocalDOMWindow* callingWindow) |
| { |
| if (!callingWindow || !callingWindow->document()) |
| return String(); |
| |
| const KURL& callingWindowURL = callingWindow->document()->url(); |
| if (callingWindowURL.isNull()) |
| return String(); |
| |
| ASSERT(!callingWindow->document()->securityOrigin()->canAccess(document()->securityOrigin())); |
| |
| SecurityOrigin* activeOrigin = callingWindow->document()->securityOrigin(); |
| String message = "Blocked a frame with origin \"" + activeOrigin->toString() + "\" from accessing a cross-origin frame."; |
| |
| // FIXME: Evaluate which details from 'crossDomainAccessErrorMessage' may safely be reported to JavaScript. |
| |
| return message; |
| } |
| |
| String LocalDOMWindow::crossDomainAccessErrorMessage(LocalDOMWindow* callingWindow) |
| { |
| if (!callingWindow || !callingWindow->document()) |
| return String(); |
| |
| const KURL& callingWindowURL = callingWindow->document()->url(); |
| if (callingWindowURL.isNull()) |
| return String(); |
| |
| ASSERT(!callingWindow->document()->securityOrigin()->canAccess(document()->securityOrigin())); |
| |
| // FIXME: This message, and other console messages, have extra newlines. Should remove them. |
| SecurityOrigin* activeOrigin = callingWindow->document()->securityOrigin(); |
| SecurityOrigin* targetOrigin = document()->securityOrigin(); |
| String message = "Blocked a frame with origin \"" + activeOrigin->toString() + "\" from accessing a frame with origin \"" + targetOrigin->toString() + "\". "; |
| |
| // Sandbox errors: Use the origin of the frames' location, rather than their actual origin (since we know that at least one will be "null"). |
| KURL activeURL = callingWindow->document()->url(); |
| KURL targetURL = document()->url(); |
| if (document()->isSandboxed(SandboxOrigin) || callingWindow->document()->isSandboxed(SandboxOrigin)) { |
| message = "Blocked a frame at \"" + SecurityOrigin::create(activeURL)->toString() + "\" from accessing a frame at \"" + SecurityOrigin::create(targetURL)->toString() + "\". "; |
| if (document()->isSandboxed(SandboxOrigin) && callingWindow->document()->isSandboxed(SandboxOrigin)) |
| return "Sandbox access violation: " + message + " Both frames are sandboxed and lack the \"allow-same-origin\" flag."; |
| if (document()->isSandboxed(SandboxOrigin)) |
| return "Sandbox access violation: " + message + " The frame being accessed is sandboxed and lacks the \"allow-same-origin\" flag."; |
| return "Sandbox access violation: " + message + " The frame requesting access is sandboxed and lacks the \"allow-same-origin\" flag."; |
| } |
| |
| // 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:'. |
| if (targetOrigin->protocol() != activeOrigin->protocol()) |
| 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"; |
| |
| // 'document.domain' errors. |
| if (targetOrigin->domainWasSetInDOM() && activeOrigin->domainWasSetInDOM()) |
| 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."; |
| if (activeOrigin->domainWasSetInDOM()) |
| 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."; |
| if (targetOrigin->domainWasSetInDOM()) |
| 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."; |
| |
| // Default. |
| return message + "Protocols, domains, and ports must match."; |
| } |
| |
| bool LocalDOMWindow::isInsecureScriptAccess(LocalDOMWindow& callingWindow, const String& urlString) |
| { |
| if (!protocolIsJavaScript(urlString)) |
| return false; |
| |
| // If this LocalDOMWindow isn't currently active in the LocalFrame, then there's no |
| // way we should allow the access. |
| // FIXME: Remove this check if we're able to disconnect LocalDOMWindow from |
| // LocalFrame on navigation: https://bugs.webkit.org/show_bug.cgi?id=62054 |
| if (isCurrentlyDisplayedInFrame()) { |
| // FIXME: Is there some way to eliminate the need for a separate "callingWindow == this" check? |
| if (&callingWindow == this) |
| return false; |
| |
| // FIXME: The name canAccess seems to be a roundabout way to ask "can execute script". |
| // Can we name the SecurityOrigin function better to make this more clear? |
| if (callingWindow.document()->securityOrigin()->canAccess(document()->securityOrigin())) |
| return false; |
| } |
| |
| printErrorMessage(crossDomainAccessErrorMessage(&callingWindow)); |
| return true; |
| } |
| |
| PassRefPtrWillBeRawPtr<LocalDOMWindow> LocalDOMWindow::open(const String& urlString, const AtomicString& frameName, const String& windowFeaturesString, |
| LocalDOMWindow* callingWindow, LocalDOMWindow* enteredWindow) |
| { |
| if (!isCurrentlyDisplayedInFrame()) |
| return nullptr; |
| Document* activeDocument = callingWindow->document(); |
| if (!activeDocument) |
| return nullptr; |
| LocalFrame* firstFrame = enteredWindow->frame(); |
| if (!firstFrame) |
| return nullptr; |
| |
| UseCounter::count(*activeDocument, UseCounter::DOMWindowOpen); |
| if (!windowFeaturesString.isEmpty()) |
| UseCounter::count(*activeDocument, UseCounter::DOMWindowOpenFeatures); |
| |
| if (!enteredWindow->allowPopUp()) { |
| // Because FrameTree::find() returns true for empty strings, we must check for empty frame names. |
| // Otherwise, illegitimate window.open() calls with no name will pass right through the popup blocker. |
| if (frameName.isEmpty() || !m_frame->tree().find(frameName)) |
| return nullptr; |
| } |
| |
| // Get the target frame for the special cases of _top and _parent. |
| // In those cases, we schedule a location change right now and return early. |
| Frame* targetFrame = 0; |
| if (frameName == "_top") |
| targetFrame = m_frame->tree().top(); |
| else if (frameName == "_parent") { |
| if (Frame* parent = m_frame->tree().parent()) |
| targetFrame = parent; |
| else |
| targetFrame = m_frame; |
| } |
| // FIXME: Navigating RemoteFrames is not yet supported. |
| if (targetFrame && targetFrame->isLocalFrame()) { |
| if (!activeDocument->canNavigate(*targetFrame)) |
| return nullptr; |
| |
| KURL completedURL = firstFrame->document()->completeURL(urlString); |
| |
| if (targetFrame->domWindow()->isInsecureScriptAccess(*callingWindow, completedURL)) |
| return targetFrame->domWindow(); |
| |
| if (urlString.isEmpty()) |
| return targetFrame->domWindow(); |
| |
| // For whatever reason, Firefox uses the first window rather than the active window to |
| // determine the outgoing referrer. We replicate that behavior here. |
| toLocalFrame(targetFrame)->navigationScheduler().scheduleLocationChange( |
| activeDocument, |
| completedURL, |
| Referrer(firstFrame->document()->outgoingReferrer(), firstFrame->document()->referrerPolicy()), |
| false); |
| return targetFrame->domWindow(); |
| } |
| |
| WindowFeatures windowFeatures(windowFeaturesString); |
| LocalFrame* result = createWindow(urlString, frameName, windowFeatures, *callingWindow, *firstFrame, *m_frame); |
| return result ? result->domWindow() : 0; |
| } |
| |
| void LocalDOMWindow::showModalDialog(const String& urlString, const String& dialogFeaturesString, |
| LocalDOMWindow* callingWindow, LocalDOMWindow* enteredWindow, PrepareDialogFunction function, void* functionContext) |
| { |
| if (!isCurrentlyDisplayedInFrame()) |
| return; |
| LocalFrame* activeFrame = callingWindow->frame(); |
| if (!activeFrame) |
| return; |
| LocalFrame* firstFrame = enteredWindow->frame(); |
| if (!firstFrame) |
| return; |
| |
| if (!canShowModalDialogNow(m_frame) || !enteredWindow->allowPopUp()) |
| return; |
| |
| UseCounter::countDeprecation(this, UseCounter::ShowModalDialog); |
| |
| WindowFeatures windowFeatures(dialogFeaturesString, screenAvailableRect(m_frame->view())); |
| LocalFrame* dialogFrame = createWindow(urlString, emptyAtom, windowFeatures, |
| *callingWindow, *firstFrame, *m_frame, function, functionContext); |
| if (!dialogFrame) |
| return; |
| UserGestureIndicatorDisabler disabler; |
| dialogFrame->host()->chrome().runModal(); |
| } |
| |
| LocalDOMWindow* LocalDOMWindow::anonymousIndexedGetter(uint32_t index) |
| { |
| LocalFrame* frame = this->frame(); |
| if (!frame) |
| return 0; |
| |
| Frame* child = frame->tree().scopedChild(index); |
| if (child) |
| return child->domWindow(); |
| |
| return 0; |
| } |
| |
| DOMWindowLifecycleNotifier& LocalDOMWindow::lifecycleNotifier() |
| { |
| return static_cast<DOMWindowLifecycleNotifier&>(LifecycleContext<LocalDOMWindow>::lifecycleNotifier()); |
| } |
| |
| PassOwnPtr<LifecycleNotifier<LocalDOMWindow> > LocalDOMWindow::createLifecycleNotifier() |
| { |
| return DOMWindowLifecycleNotifier::create(this); |
| } |
| |
| void LocalDOMWindow::trace(Visitor* visitor) |
| { |
| visitor->trace(m_document); |
| visitor->trace(m_screen); |
| visitor->trace(m_history); |
| visitor->trace(m_locationbar); |
| visitor->trace(m_menubar); |
| visitor->trace(m_personalbar); |
| visitor->trace(m_scrollbars); |
| visitor->trace(m_statusbar); |
| visitor->trace(m_toolbar); |
| visitor->trace(m_console); |
| visitor->trace(m_navigator); |
| visitor->trace(m_location); |
| visitor->trace(m_media); |
| visitor->trace(m_sessionStorage); |
| visitor->trace(m_localStorage); |
| visitor->trace(m_applicationCache); |
| visitor->trace(m_performance); |
| visitor->trace(m_css); |
| visitor->trace(m_eventQueue); |
| WillBeHeapSupplementable<LocalDOMWindow>::trace(visitor); |
| EventTargetWithInlineData::trace(visitor); |
| LifecycleContext<LocalDOMWindow>::trace(visitor); |
| } |
| |
| } // namespace blink |