Bug 1491212 part 2 - Have a new FullscreenChange superclass split from FullscreenRequest. r=smaug
authorXidorn Quan <me@upsuper.org>
Mon, 17 Sep 2018 23:20:28 +0000
changeset 492641 824f566f9043419551c6d035441928d6ba12ffac
parent 492640 12e1e7b2f4a7db4c0e0f425f37e4dbc74e444abe
child 492642 32b021561f8cfd5e6911dfacb4372aa538d2b615
push id9984
push userffxbld-merge
push dateMon, 15 Oct 2018 21:07:35 +0000
treeherdermozilla-beta@183d27ea8570 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1491212
milestone64.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1491212 part 2 - Have a new FullscreenChange superclass split from FullscreenRequest. r=smaug The next patch would create another subclass of FullscreenChange for handling fullscreen exit. Depends on D5988 Differential Revision: https://phabricator.services.mozilla.com/D5989
dom/base/Element.cpp
dom/base/FullscreenChange.h
dom/base/FullscreenRequest.h
dom/base/moz.build
dom/base/nsDocument.cpp
dom/base/nsIDocument.h
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -60,17 +60,17 @@
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/ContentEvents.h"
 #include "mozilla/DeclarationBlock.h"
 #include "mozilla/EffectSet.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/EventStates.h"
-#include "mozilla/FullscreenRequest.h"
+#include "mozilla/FullscreenChange.h"
 #include "mozilla/InternalMutationEvent.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/RestyleManager.h"
 #include "mozilla/SizeOfState.h"
 #include "mozilla/TextEditor.h"
 #include "mozilla/TextEvents.h"
 #include "nsNodeUtils.h"
 #include "mozilla/dom/DirectionalityUtils.h"
rename from dom/base/FullscreenRequest.h
rename to dom/base/FullscreenChange.h
--- a/dom/base/FullscreenRequest.h
+++ b/dom/base/FullscreenChange.h
@@ -16,46 +16,28 @@
 #include "mozilla/UniquePtr.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/Promise.h"
 #include "nsIDocument.h"
 #include "nsIScriptError.h"
 
 namespace mozilla {
 
-struct FullscreenRequest : public LinkedListElement<FullscreenRequest>
+class FullscreenChange : public LinkedListElement<FullscreenChange>
 {
-  typedef dom::Promise Promise;
+public:
+  FullscreenChange(const FullscreenChange&) = delete;
 
-  static UniquePtr<FullscreenRequest> Create(Element* aElement,
-                                             dom::CallerType aCallerType,
-                                             ErrorResult& aRv)
-  {
-    RefPtr<Promise> promise = Promise::Create(aElement->GetOwnerGlobal(), aRv);
-    return WrapUnique(new FullscreenRequest(aElement, promise.forget(),
-                                            aCallerType, true));
-  }
-
-  static UniquePtr<FullscreenRequest> CreateForRemote(Element* aElement)
+  enum ChangeType
   {
-    return WrapUnique(new FullscreenRequest(aElement, nullptr,
-                                            dom::CallerType::NonSystem,
-                                            false));
-  }
-
-  FullscreenRequest(const FullscreenRequest&) = delete;
+    eEnter,
+    eExit,
+  };
 
-  ~FullscreenRequest()
-  {
-    MOZ_COUNT_DTOR(FullscreenRequest);
-    MOZ_ASSERT_IF(mPromise,
-                  mPromise->State() != Promise::PromiseState::Pending);
-  }
-
-  dom::Element* Element() const { return mElement; }
+  ChangeType Type() const { return mType; }
   nsIDocument* Document() const { return mDocument; }
   dom::Promise* GetPromise() const { return mPromise; }
 
   void MayResolvePromise() const
   {
     if (mPromise) {
       MOZ_ASSERT(mPromise->State() == Promise::PromiseState::Pending);
       mPromise->MaybeResolveWithUndefined();
@@ -65,38 +47,88 @@ struct FullscreenRequest : public Linked
   void MayRejectPromise() const
   {
     if (mPromise) {
       MOZ_ASSERT(mPromise->State() == Promise::PromiseState::Pending);
       mPromise->MaybeReject(NS_ERROR_DOM_TYPE_ERR);
     }
   }
 
+protected:
+  typedef dom::Promise Promise;
+
+  FullscreenChange(ChangeType aType, nsIDocument* aDocument,
+                   already_AddRefed<Promise> aPromise)
+    : mType(aType)
+    , mDocument(aDocument)
+    , mPromise(aPromise)
+  {
+    MOZ_ASSERT(aDocument);
+  }
+
+  ~FullscreenChange()
+  {
+    MOZ_ASSERT_IF(mPromise,
+                  mPromise->State() != Promise::PromiseState::Pending);
+  }
+
+private:
+  ChangeType mType;
+  nsCOMPtr<nsIDocument> mDocument;
+  RefPtr<Promise> mPromise;
+};
+
+class FullscreenRequest : public FullscreenChange
+{
+public:
+  static const ChangeType kType = eEnter;
+
+  static UniquePtr<FullscreenRequest> Create(Element* aElement,
+                                             dom::CallerType aCallerType,
+                                             ErrorResult& aRv)
+  {
+    RefPtr<Promise> promise = Promise::Create(aElement->GetOwnerGlobal(), aRv);
+    return WrapUnique(new FullscreenRequest(aElement, promise.forget(),
+                                            aCallerType, true));
+  }
+
+  static UniquePtr<FullscreenRequest> CreateForRemote(Element* aElement)
+  {
+    return WrapUnique(new FullscreenRequest(aElement, nullptr,
+                                            dom::CallerType::NonSystem,
+                                            false));
+  }
+
+  ~FullscreenRequest()
+  {
+    MOZ_COUNT_DTOR(FullscreenRequest);
+  }
+
+  dom::Element* Element() const { return mElement; }
+
   // Reject the fullscreen request with the given reason.
   // It will dispatch the fullscreenerror event.
   void Reject(const char* aReason) const
   {
-    if (nsPresContext* presContext = mDocument->GetPresContext()) {
+    if (nsPresContext* presContext = Document()->GetPresContext()) {
       auto pendingEvent = MakeUnique<PendingFullscreenEvent>(
-          FullscreenEventType::Error, mDocument, mElement);
+          FullscreenEventType::Error, Document(), mElement);
       presContext->RefreshDriver()->
         ScheduleFullscreenEvent(std::move(pendingEvent));
     }
     MayRejectPromise();
     nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
                                     NS_LITERAL_CSTRING("DOM"),
-                                    mDocument,
+                                    Document(),
                                     nsContentUtils::eDOM_PROPERTIES,
                                     aReason);
   }
 
 private:
   RefPtr<dom::Element> mElement;
-  RefPtr<nsIDocument> mDocument;
-  RefPtr<dom::Promise> mPromise;
 
 public:
   // This value should be true if the fullscreen request is
   // originated from system code.
   const dom::CallerType mCallerType;
   // This value denotes whether we should trigger a NewOrigin event if
   // requesting fullscreen in its document causes the origin which is
   // fullscreen to change. We may want *not* to trigger that event if
@@ -105,19 +137,18 @@ public:
   // need to send some notification itself with the real origin.
   const bool mShouldNotifyNewOrigin;
 
 private:
   FullscreenRequest(dom::Element* aElement,
                     already_AddRefed<dom::Promise> aPromise,
                     dom::CallerType aCallerType,
                     bool aShouldNotifyNewOrigin)
-    : mElement(aElement)
-    , mDocument(aElement->OwnerDoc())
-    , mPromise(aPromise)
+    : FullscreenChange(kType, aElement->OwnerDoc(), std::move(aPromise))
+    , mElement(aElement)
     , mCallerType(aCallerType)
     , mShouldNotifyNewOrigin(aShouldNotifyNewOrigin)
   {
     MOZ_COUNT_CTOR(FullscreenRequest);
   }
 };
 
 } // namespace mozilla
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -126,17 +126,17 @@ if CONFIG['MOZ_WEBRTC']:
         'nsDOMDataChannel.h',
         'nsDOMDataChannelDeclarations.h',
     ]
 
 EXPORTS.mozilla += [
     'CORSMode.h',
     'FeedWriterEnabled.h',
     'FlushType.h',
-    'FullscreenRequest.h',
+    'FullscreenChange.h',
     'RangeBoundary.h',
     'SelectionChangeEventDispatcher.h',
     'TextInputProcessor.h',
     'UseCounter.h',
 ]
 
 EXPORTS.mozilla.dom += [
     '!UseCounterList.h',
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -53,17 +53,17 @@
 #include "mozilla/Services.h"
 #include "nsScreen.h"
 #include "ChildIterator.h"
 
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/BasicEvents.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/EventStateManager.h"
-#include "mozilla/FullscreenRequest.h"
+#include "mozilla/FullscreenChange.h"
 
 #include "mozilla/dom/Attr.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/FramingChecker.h"
 #include "mozilla/dom/HTMLSharedElement.h"
 #include "mozilla/dom/SVGUseElement.h"
@@ -10608,113 +10608,117 @@ FullscreenRoots::Remove(nsIDocument* aDo
 
 /* static */
 bool
 FullscreenRoots::IsEmpty()
 {
   return !sInstance;
 }
 
-// Any fullscreen request waiting for the widget to finish being full-
-// screen is queued here. This is declared static instead of a member
-// of nsDocument because in the majority of time, there would be at most
-// one document requesting fullscreen. We shouldn't waste the space to
-// hold for it in every document.
-class PendingFullscreenRequestList
+// Any fullscreen change waiting for the widget to finish transition
+// is queued here. This is declared static instead of a member of
+// nsDocument because in the majority of time, there would be at most
+// one document requesting or exiting fullscreen. We shouldn't waste
+// the space to hold for it in every document.
+class PendingFullscreenChangeList
 {
 public:
-  PendingFullscreenRequestList() = delete;
-
-  static void Add(UniquePtr<FullscreenRequest> aRequest)
+  PendingFullscreenChangeList() = delete;
+
+  template<typename T>
+  static void Add(UniquePtr<T> aChange)
   {
-    sList.insertBack(aRequest.release());
-  }
-
-  static const FullscreenRequest* GetLast()
+    sList.insertBack(aChange.release());
+  }
+
+  static const FullscreenChange* GetLast()
   {
     return sList.getLast();
   }
 
   enum IteratorOption
   {
     // When we are committing fullscreen changes or preparing for
     // that, we generally want to iterate all requests in the same
     // window with eDocumentsWithSameRoot option.
     eDocumentsWithSameRoot,
     // If we are removing a document from the tree, we would only
     // want to remove the requests from the given document and its
     // descendants. For that case, use eInclusiveDescendants.
     eInclusiveDescendants
   };
 
+  template<typename T>
   class Iterator
   {
   public:
     explicit Iterator(nsIDocument* aDoc, IteratorOption aOption)
-      : mCurrent(PendingFullscreenRequestList::sList.getFirst())
+      : mCurrent(PendingFullscreenChangeList::sList.getFirst())
       , mRootShellForIteration(aDoc->GetDocShell())
     {
       if (mCurrent) {
         if (mRootShellForIteration && aOption == eDocumentsWithSameRoot) {
           mRootShellForIteration->
             GetRootTreeItem(getter_AddRefs(mRootShellForIteration));
         }
         SkipToNextMatch();
       }
     }
 
-    UniquePtr<FullscreenRequest> TakeAndNext()
+    UniquePtr<T> TakeAndNext()
     {
-      auto thisRequest = TakeAndNextInternal();
+      auto thisChange = TakeAndNextInternal();
       SkipToNextMatch();
-      return thisRequest;
+      return thisChange;
     }
     bool AtEnd() const { return mCurrent == nullptr; }
 
   private:
-    UniquePtr<FullscreenRequest> TakeAndNextInternal()
+    UniquePtr<T> TakeAndNextInternal()
     {
-      UniquePtr<FullscreenRequest> thisRequest(mCurrent);
+      FullscreenChange* thisChange = mCurrent;
+      MOZ_ASSERT(thisChange->Type() == T::kType);
       mCurrent = mCurrent->removeAndGetNext();
-      return thisRequest;
+      return WrapUnique(static_cast<T*>(thisChange));
     }
     void SkipToNextMatch()
     {
       while (mCurrent) {
-        nsCOMPtr<nsIDocShellTreeItem>
-          docShell = mCurrent->Document()->GetDocShell();
-        if (!docShell) {
-          // Always automatically drop fullscreen requests which is from
-          // a document detached from the doc shell.
-          UniquePtr<FullscreenRequest> request = TakeAndNextInternal();
-          request->MayRejectPromise();
-        } else {
+        if (mCurrent->Type() == T::kType) {
+          nsCOMPtr<nsIDocShellTreeItem>
+            docShell = mCurrent->Document()->GetDocShell();
+          if (!docShell) {
+            // Always automatically drop fullscreen changes which are
+            // from a document detached from the doc shell.
+            UniquePtr<T> change = TakeAndNextInternal();
+            change->MayRejectPromise();
+            continue;
+          }
           while (docShell && docShell != mRootShellForIteration) {
             docShell->GetParent(getter_AddRefs(docShell));
           }
-          if (!docShell) {
-            // We've gone over the root, but haven't find the target
-            // ancestor, so skip this item.
-            mCurrent = mCurrent->getNext();
-          } else {
+          if (docShell) {
             break;
           }
         }
-      }
-    }
-
-    FullscreenRequest* mCurrent;
+        // The current one either don't have matched type, or isn't
+        // inside the given subtree, so skip this item.
+        mCurrent = mCurrent->getNext();
+      }
+    }
+
+    FullscreenChange* mCurrent;
     nsCOMPtr<nsIDocShellTreeItem> mRootShellForIteration;
   };
 
 private:
-  static LinkedList<FullscreenRequest> sList;
+  static LinkedList<FullscreenChange> sList;
 };
 
-/* static */ LinkedList<FullscreenRequest> PendingFullscreenRequestList::sList;
+/* static */ LinkedList<FullscreenChange> PendingFullscreenChangeList::sList;
 
 } // end namespace mozilla.
 
 nsIDocument*
 nsIDocument::GetFullscreenRoot()
 {
   nsCOMPtr<nsIDocument> root = do_QueryReferent(mFullscreenRoot);
   return root;
@@ -11362,18 +11366,18 @@ ShouldApplyFullscreenDirectly(nsIDocumen
     // fullscreen, we certainly need to make that fullscreen first.
     if (!aRootWin->GetFullScreen()) {
       return false;
     }
     // The iterator not being at end indicates there is still some
     // pending fullscreen request relates to this document. We have to
     // push the request to the pending queue so requests are handled
     // in the correct order.
-    PendingFullscreenRequestList::Iterator
-      iter(aDoc, PendingFullscreenRequestList::eDocumentsWithSameRoot);
+    PendingFullscreenChangeList::Iterator<FullscreenRequest> iter(
+      aDoc, PendingFullscreenChangeList::eDocumentsWithSameRoot);
     if (!iter.AtEnd()) {
       return false;
     }
     // We have to apply the fullscreen state directly in this case,
     // because nsGlobalWindow::SetFullscreenInternal() will do nothing
     // if it is already in fullscreen. If we do not apply the state but
     // instead add it to the queue and wait for the window as normal,
     // we would get stuck.
@@ -11406,50 +11410,50 @@ nsIDocument::RequestFullscreen(UniquePtr
   }
 
   // We don't need to check element ready before this point, because
   // if we called ApplyFullscreen, it would check that for us.
   if (!FullscreenElementReadyCheck(*aRequest)) {
     return;
   }
 
-  PendingFullscreenRequestList::Add(std::move(aRequest));
+  PendingFullscreenChangeList::Add(std::move(aRequest));
   if (XRE_GetProcessType() == GeckoProcessType_Content) {
     // If we are not the top level process, dispatch an event to make
     // our parent process go fullscreen first.
     nsContentUtils::DispatchEventOnlyToChrome(
       this, ToSupports(this), NS_LITERAL_STRING("MozDOMFullscreen:Request"),
       CanBubble::eYes, Cancelable::eNo, /* DefaultAction */ nullptr);
   } else {
     // Make the window fullscreen.
     rootWin->SetFullscreenInternal(FullscreenReason::ForFullscreenAPI, true);
   }
 }
 
 /* static */ bool
 nsIDocument::HandlePendingFullscreenRequests(nsIDocument* aDoc)
 {
   bool handled = false;
-  PendingFullscreenRequestList::Iterator iter(
-    aDoc, PendingFullscreenRequestList::eDocumentsWithSameRoot);
+  PendingFullscreenChangeList::Iterator<FullscreenRequest> iter(
+    aDoc, PendingFullscreenChangeList::eDocumentsWithSameRoot);
   while (!iter.AtEnd()) {
     UniquePtr<FullscreenRequest> request = iter.TakeAndNext();
     nsIDocument* doc = request->Document();
     if (doc->ApplyFullscreen(std::move(request))) {
       handled = true;
     }
   }
   return handled;
 }
 
 static void
 ClearPendingFullscreenRequests(nsIDocument* aDoc)
 {
-  PendingFullscreenRequestList::Iterator iter(
-    aDoc, PendingFullscreenRequestList::eInclusiveDescendants);
+  PendingFullscreenChangeList::Iterator<FullscreenRequest> iter(
+    aDoc, PendingFullscreenChangeList::eInclusiveDescendants);
   while (!iter.AtEnd()) {
     UniquePtr<FullscreenRequest> request = iter.TakeAndNext();
     request->MayRejectPromise();
   }
 }
 
 bool
 nsIDocument::ApplyFullscreen(UniquePtr<FullscreenRequest> aRequest)
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -121,17 +121,17 @@ class nsIXULWindow;
 
 namespace mozilla {
 class AbstractThread;
 class CSSStyleSheet;
 class Encoding;
 class ErrorResult;
 class EventStates;
 class EventListenerManager;
-struct FullscreenRequest;
+class FullscreenRequest;
 class PendingAnimationTracker;
 class ServoStyleSet;
 template<typename> class OwningNonNull;
 struct URLExtraData;
 
 namespace css {
 class Loader;
 class ImageLoader;