Bug 1272409 part 4: Integrate ResizeObserver with Document and reflow. r?dholbert draft
authorFariskhi Vidyan <farislab@gmail.com>
Wed, 14 Sep 2016 16:53:26 -0700
changeset 413826 4475b7bd5dbd72d9f905a955095060e73b02eecb
parent 413825 0848bd2349d335e6c581b0ded9bd6ffa5805ef80
child 413827 bc94498c3c232d45fcbbace6d8a02d11766a209b
push id29523
push userfarislab@gmail.com
push dateWed, 14 Sep 2016 23:58:19 +0000
reviewersdholbert
bugs1272409
milestone51.0a1
Bug 1272409 part 4: Integrate ResizeObserver with Document and reflow. r?dholbert MozReview-Commit-ID: F7KDJZxGnFO
dom/base/ResizeObserver.cpp
dom/base/nsDocument.cpp
dom/base/nsDocument.h
dom/base/nsIDocument.h
layout/base/nsPresShell.cpp
--- a/dom/base/ResizeObserver.cpp
+++ b/dom/base/ResizeObserver.cpp
@@ -53,17 +53,17 @@ ResizeObserver::Constructor(const Global
   nsCOMPtr<nsIDocument> document = window->GetExtantDoc();
 
   if (!document) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   RefPtr<ResizeObserver> observer = new ResizeObserver(window.forget(), aCb);
-  // TODO: Add the new ResizeObserver to document here in the later patch.
+  document->AddResizeObserver(observer);
 
   return observer.forget();
 }
 
 void
 ResizeObserver::Observe(Element* aTarget,
                         ErrorResult& aRv)
 {
@@ -78,17 +78,17 @@ ResizeObserver::Observe(Element* aTarget
     observation = new ResizeObservation(this, aTarget);
 
     mObservationMap.Put(aTarget, observation);
     mObservationList.insertBack(observation);
 
     // Per the spec, we need to trigger notification in event loop that
     // contains ResizeObserver observe call even when resize/reflow does
     // not happen.
-    // TODO: Implement the notification scheduling in the later patch.
+    aTarget->OwnerDoc()->ScheduleResizeObserversNotification();
   }
 }
 
 void
 ResizeObserver::Unobserve(Element* aTarget,
                           ErrorResult& aRv)
 {
   if (!aTarget) {
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1774,16 +1774,20 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
   for (PRCList *l = PR_LIST_HEAD(&tmp->mDOMMediaQueryLists);
        l != &tmp->mDOMMediaQueryLists; l = PR_NEXT_LINK(l)) {
     MediaQueryList *mql = static_cast<MediaQueryList*>(l);
     if (mql->HasListeners()) {
       NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mDOMMediaQueryLists item");
       cb.NoteXPCOMChild(mql);
     }
   }
+
+  if (tmp->mResizeObserverController) {
+    tmp->mResizeObserverController->Traverse(cb);
+  }
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDocument)
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(nsDocument)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
   tmp->mInUnlinkOrDeletion = true;
@@ -1875,16 +1879,20 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
        l != &tmp->mDOMMediaQueryLists; ) {
     PRCList *next = PR_NEXT_LINK(l);
     MediaQueryList *mql = static_cast<MediaQueryList*>(l);
     mql->RemoveAllListeners();
     l = next;
   }
 
   tmp->mInUnlinkOrDeletion = false;
+
+  if (tmp->mResizeObserverController) {
+    tmp->mResizeObserverController->Unlink();
+  }
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 nsresult
 nsDocument::Init()
 {
   if (mCSSLoader || mStyleImageLoader || mNodeInfoManager || mScriptLoader) {
     return NS_ERROR_ALREADY_INITIALIZED;
   }
@@ -12275,16 +12283,34 @@ nsDocument::QuerySelector(const nsAStrin
 }
 
 NS_IMETHODIMP
 nsDocument::QuerySelectorAll(const nsAString& aSelector, nsIDOMNodeList **aReturn)
 {
   return nsINode::QuerySelectorAll(aSelector, aReturn);
 }
 
+void
+nsDocument::AddResizeObserver(ResizeObserver* aResizeObserver)
+{
+  if (!mResizeObserverController) {
+    mResizeObserverController = MakeUnique<ResizeObserverController>(this);
+  }
+
+  mResizeObserverController->AddResizeObserver(aResizeObserver);
+}
+
+void
+nsDocument::ScheduleResizeObserversNotification() const
+{
+  if (mResizeObserverController) {
+    mResizeObserverController->ScheduleNotification();
+  }
+}
+
 already_AddRefed<nsIDocument>
 nsIDocument::Constructor(const GlobalObject& aGlobal,
                          ErrorResult& rv)
 {
   nsCOMPtr<nsIScriptGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
   if (!global) {
     rv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -55,16 +55,17 @@
 #include "nsISecurityEventSink.h"
 #include "nsIChannelEventSink.h"
 #include "imgIRequest.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/PendingAnimationTracker.h"
 #include "mozilla/dom/DOMImplementation.h"
+#include "mozilla/dom/ResizeObserverController.h"
 #include "mozilla/dom/StyleSheetList.h"
 #include "nsDataHashtable.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Attributes.h"
 #include "nsIDOMXPathEvaluator.h"
 #include "jsfriendapi.h"
 #include "ImportManager.h"
 #include "mozilla/LinkedList.h"
@@ -1192,16 +1193,20 @@ public:
   virtual nsINode* GetSubImportLink(uint32_t aIdx) override
   {
     return aIdx < mSubImportLinks.Length() ? mSubImportLinks[aIdx].get()
                                            : nullptr;
   }
 
   virtual void UnblockDOMContentLoaded() override;
 
+  void AddResizeObserver(mozilla::dom::ResizeObserver* aResizeObserver) override;
+
+  void ScheduleResizeObserversNotification() const override;
+
 protected:
   friend class nsNodeUtils;
   friend class nsDocumentOnStack;
 
   void IncreaseStackRefCnt()
   {
     ++mStackRefCnt;
   }
@@ -1323,16 +1328,19 @@ protected:
 
   // Apply the fullscreen state to the document, and trigger related
   // events. It returns false if the fullscreen element ready check
   // fails and nothing gets changed.
   bool ApplyFullscreen(const FullscreenRequest& aRequest);
 
   nsTArray<nsIObserver*> mCharSetObservers;
 
+  mozilla::UniquePtr<mozilla::dom::ResizeObserverController>
+    mResizeObserverController;
+
   PLDHashTable *mSubDocuments;
 
   // Array of owning references to all children
   nsAttrAndChildArray mChildren;
 
   // Pointer to our parser if we're currently in the process of being
   // parsed into.
   nsCOMPtr<nsIParser> mParser;
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -131,16 +131,17 @@ struct LifecycleCallbackArgs;
 class Link;
 class MediaQueryList;
 class GlobalObject;
 class NodeFilter;
 class NodeIterator;
 enum class OrientationType : uint32_t;
 class ProcessingInstruction;
 class Promise;
+class ResizeObserver;
 class StyleSheetList;
 class SVGDocument;
 class Touch;
 class TouchList;
 class TreeWalker;
 class UndoManager;
 class XPathEvaluator;
 class XPathExpression;
@@ -2758,16 +2759,20 @@ public:
   bool HasScriptsBlockedBySandbox();
 
   void ReportHasScrollLinkedEffect();
   bool HasScrollLinkedEffect() const
   {
     return mHasScrollLinkedEffect;
   }
 
+  virtual void AddResizeObserver(mozilla::dom::ResizeObserver* aResizeObserver) = 0;
+
+  virtual void ScheduleResizeObserversNotification() const = 0;
+
 protected:
   bool GetUseCounter(mozilla::UseCounter aUseCounter)
   {
     return mUseCounters[aUseCounter];
   }
 
   void SetChildDocumentUseCounter(mozilla::UseCounter aUseCounter)
   {
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -9400,16 +9400,20 @@ PresShell::DidDoReflow(bool aInterruptib
   HandlePostedReflowCallbacks(aInterruptible);
 
   nsCOMPtr<nsIDocShell> docShell = mPresContext->GetDocShell();
   if (docShell) {
     DOMHighResTimeStamp now = GetPerformanceNow();
     docShell->NotifyReflowObservers(aInterruptible, mLastReflowStart, now);
   }
 
+  if (!mPresContext->HasPendingInterrupt()) {
+    mDocument->ScheduleResizeObserversNotification();
+  }
+
   if (sSynthMouseMove) {
     SynthesizeMouseMove(false);
   }
 
   mPresContext->NotifyMissingFonts();
 }
 
 DOMHighResTimeStamp