Index: Source/core/dom/FullscreenElementStack.cpp |
diff --git a/Source/core/dom/FullscreenElementStack.cpp b/Source/core/dom/FullscreenElementStack.cpp |
deleted file mode 100644 |
index 81f14addbca6ede5c2a9a37abbcfd2a2328556df..0000000000000000000000000000000000000000 |
--- a/Source/core/dom/FullscreenElementStack.cpp |
+++ /dev/null |
@@ -1,609 +0,0 @@ |
-/* |
- * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
- * (C) 1999 Antti Koivisto (koivisto@kde.org) |
- * (C) 2001 Dirk Mueller (mueller@kde.org) |
- * (C) 2006 Alexey Proskuryakov (ap@webkit.org) |
- * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Inc. All rights reserved. |
- * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) |
- * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) |
- * Copyright (C) 2013 Google Inc. All rights reserved. |
- * |
- * This library is free software; you can redistribute it and/or |
- * modify it under the terms of the GNU Library General Public |
- * License as published by the Free Software Foundation; either |
- * version 2 of the License, or (at your option) any later version. |
- * |
- * This library is distributed in the hope that it will be useful, |
- * but WITHOUT ANY WARRANTY; without even the implied warranty of |
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
- * Library General Public License for more details. |
- * |
- * You should have received a copy of the GNU Library General Public License |
- * along with this library; see the file COPYING.LIB. If not, write to |
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
- * Boston, MA 02110-1301, USA. |
- * |
- */ |
- |
-#include "config.h" |
-#include "core/dom/FullscreenElementStack.h" |
- |
-#include "core/HTMLNames.h" |
-#include "core/dom/Document.h" |
-#include "core/events/Event.h" |
-#include "core/frame/FrameHost.h" |
-#include "core/frame/LocalFrame.h" |
-#include "core/frame/Settings.h" |
-#include "core/frame/UseCounter.h" |
-#include "core/html/HTMLIFrameElement.h" |
-#include "core/html/HTMLMediaElement.h" |
-#include "core/page/Chrome.h" |
-#include "core/page/ChromeClient.h" |
-#include "core/rendering/RenderFullScreen.h" |
-#include "platform/UserGestureIndicator.h" |
- |
-namespace blink { |
- |
-using namespace HTMLNames; |
- |
-static bool fullscreenIsAllowedForAllOwners(const Document& document) |
-{ |
- for (const HTMLFrameOwnerElement* owner = document.ownerElement(); owner; owner = owner->document().ownerElement()) { |
- if (!isHTMLIFrameElement(owner)) |
- return false; |
- if (!owner->hasAttribute(allowfullscreenAttr)) |
- return false; |
- } |
- return true; |
-} |
- |
-static bool fullscreenIsSupported(const Document& document) |
-{ |
- // Fullscreen is supported if there is no previously-established user preference, |
- // security risk, or platform limitation. |
- return !document.settings() || document.settings()->fullscreenSupported(); |
-} |
- |
-static bool fullscreenIsSupported(const Document& document, const Element& element) |
-{ |
- if (!document.settings() || (document.settings()->disallowFullscreenForNonMediaElements() && !isHTMLMediaElement(element))) |
- return false; |
- return fullscreenIsSupported(document); |
-} |
- |
-static bool isPrefixed(const AtomicString& type) |
-{ |
- return type == EventTypeNames::webkitfullscreenchange || type == EventTypeNames::webkitfullscreenerror; |
-} |
- |
-static PassRefPtrWillBeRawPtr<Event> createEvent(const AtomicString& type, EventTarget& target) |
-{ |
- EventInit initializer; |
- initializer.bubbles = isPrefixed(type); |
- RefPtrWillBeRawPtr<Event> event = Event::create(type, initializer); |
- event->setTarget(&target); |
- return event; |
-} |
- |
-const char* FullscreenElementStack::supplementName() |
-{ |
- return "FullscreenElementStack"; |
-} |
- |
-FullscreenElementStack& FullscreenElementStack::from(Document& document) |
-{ |
- FullscreenElementStack* fullscreen = fromIfExists(document); |
- if (!fullscreen) { |
- fullscreen = new FullscreenElementStack(document); |
- DocumentSupplement::provideTo(document, supplementName(), adoptPtrWillBeNoop(fullscreen)); |
- } |
- |
- return *fullscreen; |
-} |
- |
-FullscreenElementStack* FullscreenElementStack::fromIfExistsSlow(Document& document) |
-{ |
- return static_cast<FullscreenElementStack*>(DocumentSupplement::from(document, supplementName())); |
-} |
- |
-Element* FullscreenElementStack::fullscreenElementFrom(Document& document) |
-{ |
- if (FullscreenElementStack* found = fromIfExists(document)) |
- return found->fullscreenElement(); |
- return 0; |
-} |
- |
-Element* FullscreenElementStack::currentFullScreenElementFrom(Document& document) |
-{ |
- if (FullscreenElementStack* found = fromIfExists(document)) |
- return found->webkitCurrentFullScreenElement(); |
- return 0; |
-} |
- |
-bool FullscreenElementStack::isFullScreen(Document& document) |
-{ |
- if (FullscreenElementStack* found = fromIfExists(document)) |
- return found->webkitIsFullScreen(); |
- return false; |
-} |
- |
-FullscreenElementStack::FullscreenElementStack(Document& document) |
- : DocumentLifecycleObserver(&document) |
- , m_areKeysEnabledInFullScreen(false) |
- , m_fullScreenRenderer(nullptr) |
- , m_eventQueueTimer(this, &FullscreenElementStack::eventQueueTimerFired) |
-{ |
- document.setHasFullscreenElementStack(); |
-} |
- |
-FullscreenElementStack::~FullscreenElementStack() |
-{ |
-} |
- |
-inline Document* FullscreenElementStack::document() |
-{ |
- return lifecycleContext(); |
-} |
- |
-void FullscreenElementStack::documentWasDetached() |
-{ |
- m_eventQueue.clear(); |
- |
- if (m_fullScreenRenderer) |
- m_fullScreenRenderer->destroy(); |
- |
-#if ENABLE(OILPAN) |
- m_fullScreenElement = nullptr; |
- m_fullScreenElementStack.clear(); |
-#endif |
- |
-} |
- |
-#if !ENABLE(OILPAN) |
-void FullscreenElementStack::documentWasDisposed() |
-{ |
- // NOTE: the context dispose phase is not supported in oilpan. Please |
- // consider using the detach phase instead. |
- m_fullScreenElement = nullptr; |
- m_fullScreenElementStack.clear(); |
-} |
-#endif |
- |
-bool FullscreenElementStack::elementReady(Element& element, RequestType requestType) |
-{ |
- // A fullscreen element ready check for an element |element| returns true if all of the |
- // following are true, and false otherwise: |
- |
- // |element| is in a document. |
- if (!element.inDocument()) |
- return false; |
- |
- // |element|'s node document's fullscreen enabled flag is set. |
- if (!fullscreenIsAllowedForAllOwners(element.document())) { |
- if (requestType == PrefixedVideoRequest) |
- UseCounter::count(element.document(), UseCounter::VideoFullscreenAllowedExemption); |
- else |
- return false; |
- } |
- |
- // |element|'s node document's fullscreen element stack is either empty or its top element is an |
- // ancestor of |element|. |
- if (Element* topElement = fullscreenElementFrom(element.document())) { |
- if (!element.isDescendantOf(topElement)) |
- return false; |
- } |
- |
- // |element| has no ancestor element whose local name is iframe and namespace is the HTML |
- // namespace. |
- if (Traversal<HTMLIFrameElement>::firstAncestor(element)) |
- return false; |
- |
- return true; |
-} |
- |
-void FullscreenElementStack::requestFullscreen(Element& element, RequestType requestType) |
-{ |
- // Ignore this request if the document is not in a live frame. |
- if (!document()->isActive()) |
- return; |
- |
- do { |
- // 1. If any of the following conditions are true, terminate these steps and queue a task to fire |
- // an event named fullscreenerror with its bubbles attribute set to true on the context object's |
- // node document: |
- |
- // The fullscreen element ready check returns false. |
- if (!elementReady(element, requestType)) |
- break; |
- |
- // This algorithm is not allowed to show a pop-up: |
- // An algorithm is allowed to show a pop-up if, in the task in which the algorithm is running, either: |
- // - an activation behavior is currently being processed whose click event was trusted, or |
- // - the event listener for a trusted click event is being handled. |
- if (!UserGestureIndicator::processingUserGesture()) |
- break; |
- |
- // Fullscreen is not supported. |
- if (!fullscreenIsSupported(element.document(), element)) |
- break; |
- |
- // 2. Let doc be element's node document. (i.e. "this") |
- Document* currentDoc = document(); |
- |
- // 3. Let docs be all doc's ancestor browsing context's documents (if any) and doc. |
- Deque<Document*> docs; |
- |
- do { |
- docs.prepend(currentDoc); |
- currentDoc = currentDoc->ownerElement() ? ¤tDoc->ownerElement()->document() : 0; |
- } while (currentDoc); |
- |
- // 4. For each document in docs, run these substeps: |
- Deque<Document*>::iterator current = docs.begin(), following = docs.begin(); |
- |
- do { |
- ++following; |
- |
- // 1. Let following document be the document after document in docs, or null if there is no |
- // such document. |
- Document* currentDoc = *current; |
- Document* followingDoc = following != docs.end() ? *following : 0; |
- |
- // 2. If following document is null, push context object on document's fullscreen element |
- // stack, and queue a task to fire an event named fullscreenchange with its bubbles attribute |
- // set to true on the document. |
- if (!followingDoc) { |
- from(*currentDoc).pushFullscreenElementStack(element, requestType); |
- enqueueChangeEvent(*currentDoc, requestType); |
- continue; |
- } |
- |
- // 3. Otherwise, if document's fullscreen element stack is either empty or its top element |
- // is not following document's browsing context container, |
- Element* topElement = fullscreenElementFrom(*currentDoc); |
- if (!topElement || topElement != followingDoc->ownerElement()) { |
- // ...push following document's browsing context container on document's fullscreen element |
- // stack, and queue a task to fire an event named fullscreenchange with its bubbles attribute |
- // set to true on document. |
- from(*currentDoc).pushFullscreenElementStack(*followingDoc->ownerElement(), requestType); |
- enqueueChangeEvent(*currentDoc, requestType); |
- continue; |
- } |
- |
- // 4. Otherwise, do nothing for this document. It stays the same. |
- } while (++current != docs.end()); |
- |
- // 5. Return, and run the remaining steps asynchronously. |
- // 6. Optionally, perform some animation. |
- m_areKeysEnabledInFullScreen = requestType != PrefixedMozillaRequest && requestType != PrefixedVideoRequest; |
- document()->frameHost()->chrome().client().enterFullScreenForElement(&element); |
- |
- // 7. Optionally, display a message indicating how the user can exit displaying the context object fullscreen. |
- return; |
- } while (0); |
- |
- enqueueErrorEvent(element, requestType); |
-} |
- |
-void FullscreenElementStack::fullyExitFullscreen() |
-{ |
- // "To fully exit fullscreen act as if the exitFullscreen() method was invoked on the top-level browsing |
- // context's document and subsequently empty that document's fullscreen element stack." |
- if (!fullscreenElementFrom(document()->topDocument())) |
- return; |
- |
- // To achieve that aim, remove all the elements from the top document's stack except for the first before |
- // calling exitFullscreen(): |
- WillBeHeapVector<std::pair<RefPtrWillBeMember<Element>, RequestType> > replacementFullscreenElementStack; |
- FullscreenElementStack& topFullscreenElementStack = from(document()->topDocument()); |
- replacementFullscreenElementStack.append(topFullscreenElementStack.m_fullScreenElementStack.last()); |
- topFullscreenElementStack.m_fullScreenElementStack.swap(replacementFullscreenElementStack); |
- topFullscreenElementStack.exitFullscreen(); |
-} |
- |
-void FullscreenElementStack::exitFullscreen() |
-{ |
- // The exitFullscreen() method must run these steps: |
- |
- // 1. Let doc be the context object. (i.e. "this") |
- Document* currentDoc = document(); |
- if (!currentDoc->isActive()) |
- return; |
- |
- // 2. If doc's fullscreen element stack is empty, terminate these steps. |
- if (m_fullScreenElementStack.isEmpty()) |
- return; |
- |
- // 3. Let descendants be all the doc's descendant browsing context's documents with a non-empty fullscreen |
- // element stack (if any), ordered so that the child of the doc is last and the document furthest |
- // away from the doc is first. |
- WillBeHeapDeque<RefPtrWillBeMember<Document> > descendants; |
- for (Frame* descendant = document()->frame() ? document()->frame()->tree().traverseNext() : 0; descendant; descendant = descendant->tree().traverseNext()) { |
- if (!descendant->isLocalFrame()) |
- continue; |
- ASSERT(toLocalFrame(descendant)->document()); |
- if (fullscreenElementFrom(*toLocalFrame(descendant)->document())) |
- descendants.prepend(toLocalFrame(descendant)->document()); |
- } |
- |
- // 4. For each descendant in descendants, empty descendant's fullscreen element stack, and queue a |
- // task to fire an event named fullscreenchange with its bubbles attribute set to true on descendant. |
- for (WillBeHeapDeque<RefPtrWillBeMember<Document> >::iterator i = descendants.begin(); i != descendants.end(); ++i) { |
- ASSERT(*i); |
- RequestType requestType = from(**i).m_fullScreenElementStack.last().second; |
- from(**i).clearFullscreenElementStack(); |
- enqueueChangeEvent(**i, requestType); |
- } |
- |
- // 5. While doc is not null, run these substeps: |
- Element* newTop = 0; |
- while (currentDoc) { |
- RequestType requestType = from(*currentDoc).m_fullScreenElementStack.last().second; |
- |
- // 1. Pop the top element of doc's fullscreen element stack. |
- from(*currentDoc).popFullscreenElementStack(); |
- |
- // If doc's fullscreen element stack is non-empty and the element now at the top is either |
- // not in a document or its node document is not doc, repeat this substep. |
- newTop = fullscreenElementFrom(*currentDoc); |
- if (newTop && (!newTop->inDocument() || newTop->document() != currentDoc)) |
- continue; |
- |
- // 2. Queue a task to fire an event named fullscreenchange with its bubbles attribute set to true |
- // on doc. |
- enqueueChangeEvent(*currentDoc, requestType); |
- |
- // 3. If doc's fullscreen element stack is empty and doc's browsing context has a browsing context |
- // container, set doc to that browsing context container's node document. |
- if (!newTop && currentDoc->ownerElement()) { |
- currentDoc = ¤tDoc->ownerElement()->document(); |
- continue; |
- } |
- |
- // 4. Otherwise, set doc to null. |
- currentDoc = 0; |
- } |
- |
- // 6. Return, and run the remaining steps asynchronously. |
- // 7. Optionally, perform some animation. |
- |
- FrameHost* host = document()->frameHost(); |
- |
- // Speculative fix for engaget.com/videos per crbug.com/336239. |
- // FIXME: This check is wrong. We ASSERT(document->isActive()) above |
- // so this should be redundant and should be removed! |
- if (!host) |
- return; |
- |
- // Only exit out of full screen window mode if there are no remaining elements in the |
- // full screen stack. |
- if (!newTop) { |
- host->chrome().client().exitFullScreenForElement(m_fullScreenElement.get()); |
- return; |
- } |
- |
- // Otherwise, notify the chrome of the new full screen element. |
- host->chrome().client().enterFullScreenForElement(newTop); |
-} |
- |
-bool FullscreenElementStack::fullscreenEnabled(Document& document) |
-{ |
- // 4. The fullscreenEnabled attribute must return true if the context object has its |
- // fullscreen enabled flag set and fullscreen is supported, and false otherwise. |
- |
- // Top-level browsing contexts are implied to have their allowFullScreen attribute set. |
- return fullscreenIsAllowedForAllOwners(document) && fullscreenIsSupported(document); |
-} |
- |
-void FullscreenElementStack::willEnterFullScreenForElement(Element* element) |
-{ |
- ASSERT(element); |
- if (!document()->isActive()) |
- return; |
- |
- if (m_fullScreenRenderer) |
- m_fullScreenRenderer->unwrapRenderer(); |
- |
- m_fullScreenElement = element; |
- |
- // Create a placeholder block for a the full-screen element, to keep the page from reflowing |
- // when the element is removed from the normal flow. Only do this for a RenderBox, as only |
- // a box will have a frameRect. The placeholder will be created in setFullScreenRenderer() |
- // during layout. |
- RenderObject* renderer = m_fullScreenElement->renderer(); |
- bool shouldCreatePlaceholder = renderer && renderer->isBox(); |
- if (shouldCreatePlaceholder) { |
- m_savedPlaceholderFrameRect = toRenderBox(renderer)->frameRect(); |
- m_savedPlaceholderRenderStyle = RenderStyle::clone(renderer->style()); |
- } |
- |
- if (m_fullScreenElement != document()->documentElement()) |
- RenderFullScreen::wrapRenderer(renderer, renderer ? renderer->parent() : 0, document()); |
- |
- m_fullScreenElement->setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(true); |
- |
- // FIXME: This should not call updateStyleIfNeeded. |
- document()->setNeedsStyleRecalc(SubtreeStyleChange); |
- document()->updateRenderTreeIfNeeded(); |
-} |
- |
-void FullscreenElementStack::didEnterFullScreenForElement(Element*) |
-{ |
- if (!m_fullScreenElement) |
- return; |
- |
- if (!document()->isActive()) |
- return; |
- |
- m_fullScreenElement->didBecomeFullscreenElement(); |
- |
- m_eventQueueTimer.startOneShot(0, FROM_HERE); |
-} |
- |
-void FullscreenElementStack::willExitFullScreenForElement(Element*) |
-{ |
- if (!m_fullScreenElement) |
- return; |
- |
- if (!document()->isActive()) |
- return; |
- |
- m_fullScreenElement->willStopBeingFullscreenElement(); |
-} |
- |
-void FullscreenElementStack::didExitFullScreenForElement(Element*) |
-{ |
- if (!m_fullScreenElement) |
- return; |
- |
- if (!document()->isActive()) |
- return; |
- |
- m_fullScreenElement->setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false); |
- |
- m_areKeysEnabledInFullScreen = false; |
- |
- if (m_fullScreenRenderer) |
- m_fullScreenRenderer->unwrapRenderer(); |
- |
- m_fullScreenElement = nullptr; |
- document()->setNeedsStyleRecalc(SubtreeStyleChange); |
- |
- // When fullyExitFullscreen is called, we call exitFullscreen on the topDocument(). That means |
- // that the events will be queued there. So if we have no events here, start the timer on the |
- // exiting document. |
- Document* exitingDocument = document(); |
- if (m_eventQueue.isEmpty()) |
- exitingDocument = &document()->topDocument(); |
- ASSERT(exitingDocument); |
- from(*exitingDocument).m_eventQueueTimer.startOneShot(0, FROM_HERE); |
-} |
- |
-void FullscreenElementStack::setFullScreenRenderer(RenderFullScreen* renderer) |
-{ |
- if (renderer == m_fullScreenRenderer) |
- return; |
- |
- if (renderer && m_savedPlaceholderRenderStyle) { |
- renderer->createPlaceholder(m_savedPlaceholderRenderStyle.release(), m_savedPlaceholderFrameRect); |
- } else if (renderer && m_fullScreenRenderer && m_fullScreenRenderer->placeholder()) { |
- RenderBlock* placeholder = m_fullScreenRenderer->placeholder(); |
- renderer->createPlaceholder(RenderStyle::clone(placeholder->style()), placeholder->frameRect()); |
- } |
- |
- if (m_fullScreenRenderer) |
- m_fullScreenRenderer->unwrapRenderer(); |
- ASSERT(!m_fullScreenRenderer); |
- |
- m_fullScreenRenderer = renderer; |
-} |
- |
-void FullscreenElementStack::fullScreenRendererDestroyed() |
-{ |
- m_fullScreenRenderer = nullptr; |
-} |
- |
-void FullscreenElementStack::enqueueChangeEvent(Document& document, RequestType requestType) |
-{ |
- RefPtrWillBeRawPtr<Event> event; |
- if (requestType == UnprefixedRequest) { |
- event = createEvent(EventTypeNames::fullscreenchange, document); |
- } else { |
- ASSERT(document.hasFullscreenElementStack()); |
- FullscreenElementStack& fullscreen = from(document); |
- EventTarget* target = fullscreen.fullscreenElement(); |
- if (!target) |
- target = fullscreen.webkitCurrentFullScreenElement(); |
- if (!target) |
- target = &document; |
- event = createEvent(EventTypeNames::webkitfullscreenchange, *target); |
- } |
- m_eventQueue.append(event); |
- // NOTE: The timer is started in didEnterFullScreenForElement/didExitFullScreenForElement. |
-} |
- |
-void FullscreenElementStack::enqueueErrorEvent(Element& element, RequestType requestType) |
-{ |
- RefPtrWillBeRawPtr<Event> event; |
- if (requestType == UnprefixedRequest) |
- event = createEvent(EventTypeNames::fullscreenerror, element.document()); |
- else |
- event = createEvent(EventTypeNames::webkitfullscreenerror, element); |
- m_eventQueue.append(event); |
- m_eventQueueTimer.startOneShot(0, FROM_HERE); |
-} |
- |
-void FullscreenElementStack::eventQueueTimerFired(Timer<FullscreenElementStack>*) |
-{ |
- // Since we dispatch events in this function, it's possible that the |
- // document will be detached and GC'd. We protect it here to make sure we |
- // can finish the function successfully. |
- RefPtrWillBeRawPtr<Document> protectDocument(document()); |
- WillBeHeapDeque<RefPtrWillBeMember<Event> > eventQueue; |
- m_eventQueue.swap(eventQueue); |
- |
- while (!eventQueue.isEmpty()) { |
- RefPtrWillBeRawPtr<Event> event = eventQueue.takeFirst(); |
- Node* target = event->target()->toNode(); |
- |
- // If the element was removed from our tree, also message the documentElement. |
- if (!target->inDocument() && document()->documentElement()) { |
- ASSERT(isPrefixed(event->type())); |
- eventQueue.append(createEvent(event->type(), *document()->documentElement())); |
- } |
- |
- target->dispatchEvent(event); |
- } |
-} |
- |
-void FullscreenElementStack::elementRemoved(Element& element) |
-{ |
- // If an element |element| in a fullscreen element stack is removed from a document |document|, |
- // run these steps: |
- |
- // 1. If |element| was at the top of |document|'s fullscreen element stack, act as if the |
- // exitFullscreen() method was invoked on that document. |
- if (fullscreenElement() == &element) { |
- exitFullscreen(); |
- return; |
- } |
- |
- // 2. Otherwise, remove |element| from |document|'s fullscreen element stack. |
- for (size_t i = 0; i < m_fullScreenElementStack.size(); ++i) { |
- if (m_fullScreenElementStack[i].first.get() == &element) { |
- m_fullScreenElementStack.remove(i); |
- return; |
- } |
- } |
- |
- // NOTE: |element| was not in the fullscreen element stack. |
-} |
- |
-void FullscreenElementStack::clearFullscreenElementStack() |
-{ |
- m_fullScreenElementStack.clear(); |
-} |
- |
-void FullscreenElementStack::popFullscreenElementStack() |
-{ |
- if (m_fullScreenElementStack.isEmpty()) |
- return; |
- |
- m_fullScreenElementStack.removeLast(); |
-} |
- |
-void FullscreenElementStack::pushFullscreenElementStack(Element& element, RequestType requestType) |
-{ |
- m_fullScreenElementStack.append(std::make_pair(&element, requestType)); |
-} |
- |
-void FullscreenElementStack::trace(Visitor* visitor) |
-{ |
- visitor->trace(m_fullScreenElement); |
- visitor->trace(m_fullScreenElementStack); |
- visitor->trace(m_fullScreenRenderer); |
- visitor->trace(m_eventQueue); |
- DocumentSupplement::trace(visitor); |
-} |
- |
-} // namespace blink |