Bug 1374761 part 1. Properly restyle the viewport and its child anonymous box when we do a restyle. r?heycam draft
authorBoris Zbarsky <bzbarsky@mit.edu>
Wed, 21 Jun 2017 11:45:12 -0400
changeset 598299 a0e55f2264b812115cb8f09b8e7a43ceb78183a3
parent 597233 594416fea6e2aa6da275befeb1ca9428d6c11d58
child 598300 22243043e91381d2e2297e875de991a1b06f1c88
push id65167
push userbzbarsky@mozilla.com
push dateWed, 21 Jun 2017 15:46:49 +0000
reviewersheycam
bugs1374761
milestone56.0a1
Bug 1374761 part 1. Properly restyle the viewport and its child anonymous box when we do a restyle. r?heycam The child anon box may be an nsHTMLScrollFrame, a nsRootBoxFrame, or a nsSimplePageSequenceFrame. nsHTMLScrollFrame already knows how to deal with its anonymous box kids, nsRootBoxFrame doesn't have any, and the next changeset will deal with anon box kids of nsSimplePageSequenceFrame. MozReview-Commit-ID: 2ZV061EhRmc
layout/base/ServoRestyleManager.cpp
layout/base/nsCSSFrameConstructor.cpp
layout/generic/ViewportFrame.cpp
layout/generic/ViewportFrame.h
layout/generic/nsFrame.cpp
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/ServoRestyleManager.h"
 
 #include "mozilla/DocumentStyleRootIterator.h"
 #include "mozilla/ServoBindings.h"
 #include "mozilla/ServoStyleSet.h"
 #include "mozilla/Unused.h"
+#include "mozilla/ViewportFrame.h"
 #include "mozilla/dom/ChildIterator.h"
 #include "mozilla/dom/ElementInlines.h"
 #include "nsBlockFrame.h"
 #include "nsBulletFrame.h"
 #include "nsPlaceholderFrame.h"
 #include "nsContentUtils.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsPrintfCString.h"
@@ -424,16 +425,25 @@ ServoRestyleManager::ProcessPostTraversa
       displayContentsNode->mStyle = newContext;
     }
 
     if (styleFrame) {
       styleFrame->UpdateStyleOfOwnedAnonBoxes(*aStyleSet, aChangeList, changeHint);
       UpdateFramePseudoElementStyles(styleFrame, *aStyleSet, aChangeList);
     }
 
+    if (!aElement->GetParent()) {
+      // This is the root.  Update styles on the viewport as needed.
+      ViewportFrame* viewport =
+        do_QueryFrame(mPresContext->PresShell()->GetRootFrame());
+      if (viewport) {
+        viewport->UpdateStyle(*aStyleSet, aChangeList);
+      }
+    }
+
     // Some changes to animations don't affect the computed style and yet still
     // require the layer to be updated. For example, pausing an animation via
     // the Web Animations API won't affect an element's style but still
     // requires to update the animation on the layer.
     //
     // We can sometimes reach this when the animated style is being removed.
     // Since AddLayerChangesForAnimation checks if |styleFrame| has a transform
     // style or not, we need to call it *after* setting |newContext| to
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -2754,16 +2754,18 @@ nsCSSFrameConstructor::ConstructRootFram
   ViewportFrame* viewportFrame =
     NS_NewViewportFrame(mPresShell, viewportPseudoStyle);
 
   // XXXbz do we _have_ to pass a null content pointer to that frame?
   // Would it really kill us to pass in the root element or something?
   // What would that break?
   viewportFrame->Init(nullptr, nullptr, nullptr);
 
+  viewportFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
+
   // Bind the viewport frame to the root view
   nsView* rootView = mPresShell->GetViewManager()->GetRootView();
   viewportFrame->SetView(rootView);
 
   viewportFrame->SyncFrameViewProperties(rootView);
   nsContainerFrame::SyncWindowProperties(mPresShell->GetPresContext(), viewportFrame,
                                          rootView, nullptr, nsContainerFrame::SET_ASYNC);
 
--- a/layout/generic/ViewportFrame.cpp
+++ b/layout/generic/ViewportFrame.cpp
@@ -410,15 +410,44 @@ ViewportFrame::ComputeCustomOverflow(nsO
     PresContext()->PresShell()->GetRootScrollFrameAsScrollable();
   if (rootScrollFrame && !rootScrollFrame->IsIgnoringViewportClipping()) {
     return false;
   }
 
   return nsContainerFrame::ComputeCustomOverflow(aOverflowAreas);
 }
 
+void
+ViewportFrame::UpdateStyle(ServoStyleSet& aStyleSet,
+                           nsStyleChangeList& aChangeList)
+{
+  nsStyleContext* oldContext = StyleContext();
+  nsIAtom* pseudo = oldContext->GetPseudo();
+  RefPtr<nsStyleContext> newContext =
+    aStyleSet.ResolveInheritingAnonymousBoxStyle(pseudo, nullptr);
+
+  // We're special because we have a null GetContent(), so don't call things
+  // like UpdateStyleOfOwnedChildFrame that try to append changes for the
+  // content to the change list.  Nor do we computed a changehint, since we have
+  // no way to apply it anyway.
+  newContext->EnsureSameStructsCached(oldContext);
+
+  MOZ_ASSERT(!GetNextContinuation(), "Viewport has continuations?");
+  SetStyleContext(newContext);
+
+  UpdateStyleOfOwnedAnonBoxes(aStyleSet, aChangeList, nsChangeHint_Empty);
+}
+
+void
+ViewportFrame::AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult)
+{
+  if (mFrames.NotEmpty()) {
+    aResult.AppendElement(mFrames.FirstChild());
+  }
+}
+
 #ifdef DEBUG_FRAME_DUMP
 nsresult
 ViewportFrame::GetFrameName(nsAString& aResult) const
 {
   return MakeFrameName(NS_LITERAL_STRING("Viewport"), aResult);
 }
 #endif
--- a/layout/generic/ViewportFrame.h
+++ b/layout/generic/ViewportFrame.h
@@ -67,16 +67,27 @@ public:
   /**
    * Adjust aReflowInput to account for scrollbars and pres shell
    * GetScrollPositionClampingScrollPortSizeSet and
    * GetContentDocumentFixedPositionMargins adjustments.
    * @return the rect to use as containing block rect
    */
   nsRect AdjustReflowInputAsContainingBlock(ReflowInput* aReflowInput) const;
 
+  /**
+   * Update our style (and recursively the styles of any anonymous boxes we
+   * might own)
+   */
+  void UpdateStyle(ServoStyleSet& aStyleSet, nsStyleChangeList& aChangeList);
+
+  /**
+   * Return our single anonymous box child.
+   */
+  void AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult) override;
+
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override;
 #endif
 
 protected:
   ViewportFrame(nsStyleContext* aContext, ClassID aID)
     : nsContainerFrame(aContext, aID)
     , mView(nullptr)
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -10203,17 +10203,18 @@ nsFrame::BoxMetrics() const
 void
 nsIFrame::UpdateStyleOfChildAnonBox(nsIFrame* aChildFrame,
                                     ServoStyleSet& aStyleSet,
                                     nsStyleChangeList& aChangeList,
                                     nsChangeHint aHintForThisFrame)
 {
   MOZ_ASSERT(aChildFrame->GetParent() == this,
              "This should only be used for children!");
-  MOZ_ASSERT(aChildFrame->GetContent() == GetContent(),
+  MOZ_ASSERT((!GetContent() && IsViewportFrame()) ||
+             aChildFrame->GetContent() == GetContent(),
              "What content node is it a frame for?");
   MOZ_ASSERT(!aChildFrame->GetPrevContinuation(),
              "Only first continuations should end up here");
 
   // We could force the caller to pass in the pseudo, since some callers know it
   // statically...  But this API is a bit nicer.
   nsIAtom* pseudo = aChildFrame->StyleContext()->GetPseudo();
   MOZ_ASSERT(nsCSSAnonBoxes::IsAnonBox(pseudo), "Child is not an anon box?");