Bug 1543315 - part 10: Mark nsIPresShell::GoToAnchor() and nsIPresShell::ScrollToAnchor() as MOZ_CAN_RUN_SCRIPT r=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Tue, 23 Apr 2019 01:27:47 +0000
changeset 470446 3d921a5274f511f3da58cc0499239299f092ad96
parent 470445 2ef93e029730573bc86953be52d93e6b73198c9d
child 470447 7d67598c90435110cb0ee046e14750306f1d32f6
push id35906
push useraciure@mozilla.com
push dateTue, 23 Apr 2019 22:14:56 +0000
treeherdermozilla-central@0ce3633f8b80 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1543315
milestone68.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 1543315 - part 10: Mark nsIPresShell::GoToAnchor() and nsIPresShell::ScrollToAnchor() as MOZ_CAN_RUN_SCRIPT r=smaug Next, we should mark `PresShell::ScrollContentIntoView()` as `MOZ_CAN_RUN_SCRIPT` because it's used widely. This patch marks its `PresShell` users, `GoToAnchor()` and `ScrollToAnchor()`, as `MOZ_CAN_RUN_SCRIPT`. Additionally, this patch moves them from `nsIPresShell` to `PresShell` because all callers refers `PresShell` directly. Differential Revision: https://phabricator.services.mozilla.com/D28319
docshell/base/nsDocShell.h
dom/base/Document.h
dom/base/nsContentSink.cpp
dom/base/nsContentSink.h
layout/base/PresShell.cpp
layout/base/PresShell.h
layout/base/nsDocumentViewer.cpp
layout/base/nsIPresShell.h
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -393,16 +393,17 @@ class nsDocShell final : public nsDocLoa
     return mBrowsingContext;
   }
 
   /**
    * Loads the given URI. See comments on nsDocShellLoadState members for more
    * information on information used. aDocShell and aRequest come from
    * onLinkClickSync, which is triggered during form submission.
    */
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   nsresult InternalLoad(nsDocShellLoadState* aLoadState,
                         nsIDocShell** aDocShell, nsIRequest** aRequest);
 
   // Clear the document's storage access flag if needed.
   void MaybeClearStorageAccessFlag();
 
  private:  // member functions
   friend class nsDSURIContentListener;
@@ -557,16 +558,17 @@ class nsDocShell final : public nsDocLoa
 
   nsresult DoChannelLoad(nsIChannel* aChannel, nsIURILoader* aURILoader,
                          bool aBypassClassifier);
 
   nsresult OpenInitializedChannel(nsIChannel* aChannel,
                                   nsIURILoader* aURILoader,
                                   uint32_t aOpenFlags);
 
+  MOZ_CAN_RUN_SCRIPT
   nsresult ScrollToAnchor(bool aCurHasRef, bool aNewHasRef,
                           nsACString& aNewHash, uint32_t aLoadType);
 
   // Returns true if would have called FireOnLocationChange,
   // but did not because aFireOnLocationChange was false on entry.
   // In this case it is the caller's responsibility to ensure
   // FireOnLocationChange is called.
   // In all other cases false is returned.
@@ -916,16 +918,17 @@ class nsDocShell final : public nsDocLoa
   // is either nsIBrowserDOMWindow::OPEN_CURRENTWINDOW or
   // nsIBrowserDOMWindow::OPEN_NEWWINDOW.
   nsresult MaybeHandleLoadDelegate(nsDocShellLoadState* aLoadState,
                                    uint32_t aWindowType, bool* aDidHandleLoad);
 
   // Check to see if we're loading a prior history entry in the same document.
   // If so, handle the scrolling or other action required instead of continuing
   // with new document navigation.
+  MOZ_CAN_RUN_SCRIPT
   nsresult MaybeHandleSameDocumentNavigation(nsDocShellLoadState* aLoadState,
                                              bool* aWasSameDocument);
 
  private:  // data members
   static nsIURIFixup* sURIFixup;
 
   // Cached value of the "browser.xul.error_pages.enabled" preference.
   static bool sUseErrorPages;
--- a/dom/base/Document.h
+++ b/dom/base/Document.h
@@ -2939,17 +2939,17 @@ class Document : public nsINode,
   EventStates GetDocumentState() const { return mDocumentState; }
 
   nsISupports* GetCurrentContentSink();
 
   void SetAutoFocusElement(Element* aAutoFocusElement);
   void TriggerAutoFocus();
 
   void SetScrollToRef(nsIURI* aDocumentURI);
-  void ScrollToRef();
+  MOZ_CAN_RUN_SCRIPT void ScrollToRef();
   void ResetScrolledToRefAlready() { mScrolledToRefAlready = false; }
 
   void SetChangeScrollPosWhenScrollingToRef(bool aValue) {
     mChangeScrollPosWhenScrollingToRef = aValue;
   }
 
   using DocumentOrShadowRoot::GetElementById;
   using DocumentOrShadowRoot::GetElementsByClassName;
--- a/dom/base/nsContentSink.cpp
+++ b/dom/base/nsContentSink.cpp
@@ -1153,17 +1153,20 @@ void nsContentSink::ProcessOfflineManife
     }
     default:
       NS_ASSERTION(false,
                    "Cache selection algorithm didn't decide on proper action");
       break;
   }
 }
 
-void nsContentSink::ScrollToRef() { mDocument->ScrollToRef(); }
+void nsContentSink::ScrollToRef() {
+  RefPtr<Document> document = mDocument;
+  document->ScrollToRef();
+}
 
 void nsContentSink::StartLayout(bool aIgnorePendingSheets) {
   AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("nsContentSink::StartLayout", LAYOUT,
                                         mDocumentURI->GetSpecOrDefault());
 
   if (mLayoutStarted) {
     // Nothing to do here
     return;
--- a/dom/base/nsContentSink.h
+++ b/dom/base/nsContentSink.h
@@ -231,17 +231,17 @@ class nsContentSink : public nsICSSLoade
 
   // For Preconnect() aHref can either be the usual
   // URI format or of the form "//www.hostname.com" without a scheme.
   void Preconnect(const nsAString& aHref, const nsAString& aCrossOrigin);
 
  protected:
   // Tries to scroll to the URI's named anchor. Once we've successfully
   // done that, further calls to this method will be ignored.
-  void ScrollToRef();
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY void ScrollToRef();
 
   // Start layout.  If aIgnorePendingSheets is true, this will happen even if
   // we still have stylesheet loads pending.  Otherwise, we'll wait until the
   // stylesheets are all done loading.
  public:
   void StartLayout(bool aIgnorePendingSheets);
 
   static void NotifyDocElementCreated(Document* aDoc);
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -819,18 +819,18 @@ nsIPresShell::nsIPresShell()
       mFontSizeInflationLineThreshold(0),
       mInFlush(false),
       mCurrentEventFrame(nullptr) {
 }
 
 PresShell::PresShell()
     : mCaretEnabled(false),
       mMouseLocation(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE),
+      mAPZFocusSequenceNumber(0),
       mActiveSuppressDisplayport(0),
-      mAPZFocusSequenceNumber(0),
       mDocumentLoading(false),
       mNoDelayedMouseEvents(false),
       mNoDelayedKeyEvents(false),
       mApproximateFrameVisibilityVisited(false),
       mNextPaintCompressed(false),
       mHasCSSBackgroundColor(false),
       mIsLastChromeOnlyEscapeKeyConsumed(false),
       mHasReceivedPaintMessage(false),
@@ -2993,18 +2993,18 @@ already_AddRefed<gfxContext> nsIPresShel
     // However, width and height, may be outside of the reasonable range
     // so rc may still be null.
     rc = devCtx->CreateReferenceRenderingContext();
   }
 
   return rc ? rc.forget() : nullptr;
 }
 
-nsresult nsIPresShell::GoToAnchor(const nsAString& aAnchorName, bool aScroll,
-                                  uint32_t aAdditionalScrollFlags) {
+nsresult PresShell::GoToAnchor(const nsAString& aAnchorName, bool aScroll,
+                               uint32_t aAdditionalScrollFlags) {
   if (!mDocument) {
     return NS_ERROR_FAILURE;
   }
 
   const Element* root = mDocument->GetRootElement();
   if (root && root->IsSVGElement(nsGkAtoms::svg)) {
     // We need to execute this even if there is an empty anchor name
     // so that any existing SVG fragment identifier effect is removed
@@ -3159,17 +3159,17 @@ nsresult nsIPresShell::GoToAnchor(const 
     nsAccessibilityService* accService = AccService();
     if (accService) accService->NotifyOfAnchorJumpTo(anchorTarget);
   }
 #endif
 
   return rv;
 }
 
-nsresult nsIPresShell::ScrollToAnchor() {
+nsresult PresShell::ScrollToAnchor() {
   if (!mLastAnchorScrolledTo) {
     return NS_OK;
   }
   NS_ASSERTION(mDidInitialize, "should have done initial reflow by now");
 
   nsIScrollableFrame* rootScroll = GetRootScrollFrameAsScrollable();
   if (!rootScroll ||
       mLastAnchorScrollPositionY != rootScroll->GetScrollPosition().y) {
--- a/layout/base/PresShell.h
+++ b/layout/base/PresShell.h
@@ -357,16 +357,39 @@ class PresShell final : public nsIPresSh
         aKeyPressEventModel ==
         dom::HTMLDocument_Binding::KEYPRESS_EVENT_MODEL_SPLIT;
   }
 
   static PresShell* GetShellForEventTarget(nsIFrame* aFrame,
                                            nsIContent* aContent);
   static PresShell* GetShellForTouchEvent(WidgetGUIEvent* aEvent);
 
+  /**
+   * Informs the pres shell that the document is now at the anchor with
+   * the given name.  If |aScroll| is true, scrolls the view of the
+   * document so that the anchor with the specified name is displayed at
+   * the top of the window.  If |aAnchorName| is empty, then this informs
+   * the pres shell that there is no current target, and |aScroll| must
+   * be false.  If |aAdditionalScrollFlags| is nsIPresShell::SCROLL_SMOOTH_AUTO
+   * and |aScroll| is true, the scrolling may be performed with an animation.
+   */
+  MOZ_CAN_RUN_SCRIPT
+  nsresult GoToAnchor(const nsAString& aAnchorName, bool aScroll,
+                      uint32_t aAdditionalScrollFlags = 0);
+
+  /**
+   * Tells the presshell to scroll again to the last anchor scrolled to by
+   * GoToAnchor, if any. This scroll only happens if the scroll
+   * position has not changed since the last GoToAnchor. This is called
+   * by nsDocumentViewer::LoadComplete. This clears the last anchor
+   * scrolled to by GoToAnchor (we don't want to keep it alive if it's
+   * removed from the DOM), so don't call this more than once.
+   */
+  MOZ_CAN_RUN_SCRIPT nsresult ScrollToAnchor();
+
  private:
   ~PresShell();
 
   friend class ::AutoPointerEventTargetUpdater;
 
   // ProcessReflowCommands returns whether we processed all our dirty roots
   // without interruptions.
   MOZ_CAN_RUN_SCRIPT bool ProcessReflowCommands(bool aInterruptible);
@@ -1386,23 +1409,27 @@ class PresShell final : public nsIPresSh
 
   TimeStamp mLoadBegin;  // used to time loads
 
   // Information about live content (which still stay in DOM tree).
   // Used in case we need re-dispatch event after sending pointer event,
   // when target of pointer event was deleted during executing user handlers.
   nsCOMPtr<nsIContent> mPointerEventTarget;
 
-  int32_t mActiveSuppressDisplayport;
+  nsCOMPtr<nsIContent> mLastAnchorScrolledTo;
 
   // The focus sequence number of the last processed input event
   uint64_t mAPZFocusSequenceNumber;
   // The focus information needed for async keyboard scrolling
   FocusTarget mAPZFocusTarget;
 
+  nscoord mLastAnchorScrollPositionY = 0;
+
+  int32_t mActiveSuppressDisplayport;
+
   bool mDocumentLoading : 1;
   bool mNoDelayedMouseEvents : 1;
   bool mNoDelayedKeyEvents : 1;
 
   bool mApproximateFrameVisibilityVisited : 1;
 
   bool mNextPaintCompressed : 1;
 
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -344,16 +344,17 @@ class nsDocumentViewer final : public ns
   nsresult InitInternal(nsIWidget* aParentWidget, nsISupports* aState,
                         const nsIntRect& aBounds, bool aDoCreation,
                         bool aNeedMakeCX = true,
                         bool aForceSetNewDocument = true);
   /**
    * @param aDoInitialReflow set to true if you want to kick off the initial
    * reflow
    */
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   nsresult InitPresentationStuff(bool aDoInitialReflow);
 
   already_AddRefed<nsINode> GetPopupNode();
   already_AddRefed<nsINode> GetPopupLinkNode();
   already_AddRefed<nsIImageLoadingContent> GetPopupImageNode();
 
   MOZ_CAN_RUN_SCRIPT_BOUNDARY
   nsresult GetContentSizeInternal(int32_t* aWidth, int32_t* aHeight,
@@ -819,17 +820,18 @@ nsresult nsDocumentViewer::InitPresentat
       mDocument->RemoveEventListener(NS_LITERAL_STRING("focus"),
                                      oldFocusListener, false);
       mDocument->RemoveEventListener(NS_LITERAL_STRING("blur"),
                                      oldFocusListener, false);
     }
   }
 
   if (aDoInitialReflow && mDocument) {
-    mDocument->ScrollToRef();
+    nsCOMPtr<Document> document = mDocument;
+    document->ScrollToRef();
   }
 
   return NS_OK;
 }
 
 static nsPresContext* CreatePresContext(Document* aDocument,
                                         nsPresContext::nsPresContextType aType,
                                         nsView* aContainerView) {
@@ -1131,17 +1133,18 @@ nsDocumentViewer::LoadComplete(nsresult 
           !isInUnload) {
         mDocument->OnPageShow(restoring, nullptr);
       }
     }
   }
 
   if (!mStopped) {
     if (mDocument) {
-      mDocument->ScrollToRef();
+      nsCOMPtr<Document> document = mDocument;
+      document->ScrollToRef();
     }
 
     // Now that the document has loaded, we can tell the presshell
     // to unsuppress painting.
     if (mPresShell) {
       RefPtr<PresShell> presShell = mPresShell;
       presShell->UnsuppressPainting();
       // mPresShell could have been removed now, see bug 378682/421432
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -666,38 +666,16 @@ class nsIPresShell : public nsStubDocume
 
   /**
    * Get a reference rendering context. This is a context that should not
    * be rendered to, but is suitable for measuring text and performing
    * other non-rendering operations. Guaranteed to return non-null.
    */
   already_AddRefed<gfxContext> CreateReferenceRenderingContext();
 
-  /**
-   * Informs the pres shell that the document is now at the anchor with
-   * the given name.  If |aScroll| is true, scrolls the view of the
-   * document so that the anchor with the specified name is displayed at
-   * the top of the window.  If |aAnchorName| is empty, then this informs
-   * the pres shell that there is no current target, and |aScroll| must
-   * be false.  If |aAdditionalScrollFlags| is nsIPresShell::SCROLL_SMOOTH_AUTO
-   * and |aScroll| is true, the scrolling may be performed with an animation.
-   */
-  nsresult GoToAnchor(const nsAString& aAnchorName, bool aScroll,
-                      uint32_t aAdditionalScrollFlags = 0);
-
-  /**
-   * Tells the presshell to scroll again to the last anchor scrolled to by
-   * GoToAnchor, if any. This scroll only happens if the scroll
-   * position has not changed since the last GoToAnchor. This is called
-   * by nsDocumentViewer::LoadComplete. This clears the last anchor
-   * scrolled to by GoToAnchor (we don't want to keep it alive if it's
-   * removed from the DOM), so don't call this more than once.
-   */
-  nsresult ScrollToAnchor();
-
   enum {
     SCROLL_TOP = 0,
     SCROLL_BOTTOM = 100,
     SCROLL_LEFT = 0,
     SCROLL_RIGHT = 100,
     SCROLL_CENTER = 50,
     SCROLL_MINIMUM = -1
   };
@@ -1878,24 +1856,22 @@ class nsIPresShell : public nsStubDocume
 #endif
 
 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
   // We track allocated pointers in a debug-only hashtable to assert against
   // missing/double frees.
   nsTHashtable<nsPtrHashKey<void>> mAllocatedPointers;
 #endif
 
-  nsCOMPtr<nsIContent> mLastAnchorScrolledTo;
   // Information needed to properly handle scrolling content into view if the
   // pre-scroll reflow flush can be interrupted.  mContentToScrollTo is non-null
   // between the initial scroll attempt and the first time we finish processing
   // all our dirty roots.  mContentToScrollTo has a content property storing the
   // details for the scroll operation, see ScrollIntoViewData above.
   nsCOMPtr<nsIContent> mContentToScrollTo;
-  nscoord mLastAnchorScrollPositionY = 0;
 
   // Count of the number of times this presshell has been painted to a window.
   uint64_t mPaintCount;
 
   nsSize mVisualViewportSize;
 
   mozilla::Maybe<nsPoint> mVisualViewportOffset;