Bug 1344386 - Don't look for overlapping change hints in stylo documents. r=emilio
authorBobby Holley <bobbyholley@gmail.com>
Fri, 03 Mar 2017 14:42:51 -0800
changeset 346387 1112d053e28239ef764d89620749e05fc2e4777b
parent 346343 dd92d0734a266dab534af530c8ae35670aedd282
child 346388 713c0a78c2c12b999dcba625c358405531c468bc
push id31467
push usercbook@mozilla.com
push dateWed, 08 Mar 2017 13:18:20 +0000
treeherdermozilla-central@becff35a0bed [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersemilio
bugs1344386
milestone55.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 1344386 - Don't look for overlapping change hints in stylo documents. r=emilio MozReview-Commit-ID: 9wK8TTXolPM
layout/base/GeckoRestyleManager.cpp
layout/base/PresShell.cpp
layout/base/RestyleTracker.cpp
layout/base/ServoRestyleManager.cpp
layout/base/nsStyleChangeList.cpp
layout/base/nsStyleChangeList.h
layout/generic/nsFrame.cpp
--- a/layout/base/GeckoRestyleManager.cpp
+++ b/layout/base/GeckoRestyleManager.cpp
@@ -3467,17 +3467,17 @@ void
 GeckoRestyleManager::ComputeAndProcessStyleChange(
     nsIFrame*              aFrame,
     nsChangeHint           aMinChange,
     RestyleTracker&        aRestyleTracker,
     nsRestyleHint          aRestyleHint,
     const RestyleHintData& aRestyleHintData)
 {
   MOZ_ASSERT(mReframingStyleContexts, "should have rsc");
-  nsStyleChangeList changeList;
+  nsStyleChangeList changeList(StyleBackendType::Gecko);
   nsTArray<ElementRestyler::ContextToClear> contextsToClear;
 
   // swappedStructOwners needs to be kept alive until after
   // ProcessRestyledFrames and ClearCachedInheritedStyleDataOnDescendants
   // calls; see comment in ElementRestyler::Restyle.
   nsTArray<RefPtr<nsStyleContext>> swappedStructOwners;
   ElementRestyler::ComputeStyleChangeFor(aFrame, &changeList, aMinChange,
                                          aRestyleTracker, aRestyleHint,
@@ -3512,17 +3512,17 @@ GeckoRestyleManager::ComputeAndProcessSt
   nsTArray<nsCSSSelector*> selectorsForDescendants;
   nsTArray<nsIContent*> visibleKidsOfHiddenElement;
   nsTArray<ElementRestyler::ContextToClear> contextsToClear;
 
   // swappedStructOwners needs to be kept alive until after
   // ProcessRestyledFrames and ClearCachedInheritedStyleDataOnDescendants
   // calls; see comment in ElementRestyler::Restyle.
   nsTArray<RefPtr<nsStyleContext>> swappedStructOwners;
-  nsStyleChangeList changeList;
+  nsStyleChangeList changeList(StyleBackendType::Gecko);
   ElementRestyler r(frame->PresContext(), aElement, &changeList, aMinChange,
                     aRestyleTracker, selectorsForDescendants, treeMatchContext,
                     visibleKidsOfHiddenElement, contextsToClear,
                     swappedStructOwners);
   r.RestyleChildrenOfDisplayContentsElement(frame, aNewContext, aMinChange,
                                             aRestyleTracker,
                                             aRestyleHint, aRestyleHintData);
   ProcessRestyledFrames(changeList);
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -2938,17 +2938,17 @@ PresShell::RecreateFramesFor(nsIContent*
   NS_ASSERTION(mViewManager, "Should have view manager");
 
   // Have to make sure that the content notifications are flushed before we
   // start messing with the frame model; otherwise we can get content doubling.
   mDocument->FlushPendingNotifications(FlushType::ContentAndNotify);
 
   nsAutoScriptBlocker scriptBlocker;
 
-  nsStyleChangeList changeList;
+  nsStyleChangeList changeList(mPresContext->StyleSet()->BackendType());
   changeList.AppendChange(nullptr, aContent, nsChangeHint_ReconstructFrame);
 
   // Mark ourselves as not safe to flush while we're doing frame construction.
   ++mChangeNestCount;
   RestyleManager* restyleManager = mPresContext->RestyleManager();
   restyleManager->ProcessRestyledFrames(changeList);
   restyleManager->FlushOverflowChangedTracker();
   --mChangeNestCount;
@@ -9580,17 +9580,17 @@ PresShell::Observe(nsISupports* aSubject
       mDocument->FlushPendingNotifications(FlushType::ContentAndNotify);
 
       if (weakRoot.IsAlive()) {
         WalkFramesThroughPlaceholders(mPresContext, rootFrame,
                                       &ReResolveMenusAndTrees, nullptr);
 
         // Because "chrome:" URL equality is messy, reframe image box
         // frames (hack!).
-        nsStyleChangeList changeList;
+        nsStyleChangeList changeList(mPresContext->StyleSet()->BackendType());
         WalkFramesThroughPlaceholders(mPresContext, rootFrame,
                                       ReframeImageBoxes, &changeList);
         // Mark ourselves as not safe to flush while we're doing frame
         // construction.
         {
           nsAutoScriptBlocker scriptBlocker;
           ++mChangeNestCount;
           RestyleManager* restyleManager = mPresContext->RestyleManager();
--- a/layout/base/RestyleTracker.cpp
+++ b/layout/base/RestyleTracker.cpp
@@ -93,17 +93,17 @@ RestyleTracker::ProcessOneRestyle(Elemen
     }
 #endif
     mRestyleManager->RestyleElement(aElement, primaryFrame, aChangeHint,
                                     *this, aRestyleHint, aRestyleHintData);
   } else if (aChangeHint &&
              (primaryFrame ||
               (aChangeHint & nsChangeHint_ReconstructFrame))) {
     // Don't need to recompute style; just apply the hint
-    nsStyleChangeList changeList;
+    nsStyleChangeList changeList(StyleBackendType::Gecko);
     changeList.AppendChange(primaryFrame, aElement, aChangeHint);
     mRestyleManager->ProcessRestyledFrames(changeList);
   }
 }
 
 void
 RestyleTracker::DoProcessRestyles()
 {
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -382,17 +382,17 @@ ServoRestyleManager::ProcessPendingResty
   // in a loop because certain rare paths in the frame constructor (like
   // uninstalling XBL bindings) can trigger additional style validations.
   mInStyleRefresh = true;
   while (styleSet->StyleDocument()) {
     PresContext()->EffectCompositor()->ClearElementsToRestyle();
 
     // Recreate style contexts, and queue up change hints (which also handle
     // lazy frame construction).
-    nsStyleChangeList currentChanges;
+    nsStyleChangeList currentChanges(StyleBackendType::Servo);
     DocumentStyleRootIterator iter(doc);
     while (Element* root = iter.GetNextStyleRoot()) {
       ProcessPostTraversal(root, nullptr, styleSet, currentChanges);
     }
 
     // Process the change hints.
     //
     // Unfortunately, the frame constructor can generate new change hints while
--- a/layout/base/nsStyleChangeList.cpp
+++ b/layout/base/nsStyleChangeList.cpp
@@ -36,19 +36,27 @@ nsStyleChangeList::AppendChange(nsIFrame
               aHint & nsChangeHint_ReconstructFrame),
              "Shouldn't be trying to restyle non-elements directly, "
              "except if it's a display:contents child or a text node "
              "doing lazy frame construction");
   MOZ_ASSERT(!(aHint & nsChangeHint_AllReflowHints) ||
              (aHint & nsChangeHint_NeedReflow),
              "Reflow hint bits set without actually asking for a reflow");
 
-  // Filter out all other changes for same content
-  if (!IsEmpty() && (aHint & nsChangeHint_ReconstructFrame)) {
-    if (aContent) {
+  // If Servo fires reconstruct at a node, it is the only change hint fired at
+  // that node.
+  if (IsServo()) {
+    for (size_t i = 0; i < Length(); ++i) {
+      MOZ_ASSERT_IF(aContent && ((aHint | (*this)[i].mHint) & nsChangeHint_ReconstructFrame),
+                    (*this)[i].mContent != aContent);
+    }
+  } else {
+    // Filter out all other changes for same content for Gecko (Servo asserts against this
+    // case above).
+    if (aContent && (aHint & nsChangeHint_ReconstructFrame)) {
       // NOTE: This is captured by reference to please static analysis.
       // Capturing it by value as a pointer should be fine in this case.
       RemoveElementsBy([&](const nsStyleChangeData& aData) {
         return aData.mContent == aContent;
       });
     }
   }
 
--- a/layout/base/nsStyleChangeList.h
+++ b/layout/base/nsStyleChangeList.h
@@ -7,16 +7,17 @@
  * a list of the recomputation that needs to be done in response to a
  * style change
  */
 
 #ifndef nsStyleChangeList_h___
 #define nsStyleChangeList_h___
 
 #include "mozilla/Attributes.h"
+#include "mozilla/StyleBackendType.h"
 
 #include "nsChangeHint.h"
 #include "nsCOMPtr.h"
 
 class nsIFrame;
 class nsIContent;
 
 struct nsStyleChangeData
@@ -34,14 +35,34 @@ class nsStyleChangeList : private AutoTA
 public:
   using base_type::begin;
   using base_type::end;
   using base_type::IsEmpty;
   using base_type::Clear;
   using base_type::Length;
   using base_type::operator[];
 
-  nsStyleChangeList() { MOZ_COUNT_CTOR(nsStyleChangeList); }
+  nsStyleChangeList(mozilla::StyleBackendType aType) :
+    mType(aType) { MOZ_COUNT_CTOR(nsStyleChangeList); }
   ~nsStyleChangeList() { MOZ_COUNT_DTOR(nsStyleChangeList); }
   void AppendChange(nsIFrame* aFrame, nsIContent* aContent, nsChangeHint aHint);
+
+  // Starting from the end of the list, removes all changes until the list is
+  // empty or an element with |mContent != aContent| is found.
+  void PopChangesForContent(nsIContent* aContent)
+  {
+    while (Length() > 0) {
+      if (LastElement().mContent == aContent) {
+        RemoveElementAt(Length() - 1);
+      } else {
+        break;
+      }
+    }
+  }
+
+  bool IsGecko() const { return mType == mozilla::StyleBackendType::Gecko; }
+  bool IsServo() const { return mType == mozilla::StyleBackendType::Servo; }
+
+private:
+  mozilla::StyleBackendType mType;
 };
 
 #endif /* nsStyleChangeList_h___ */
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -10082,16 +10082,21 @@ nsFrame::UpdateStyleOfChildAnonBox(nsIFr
   //    anonymous boxed directly.
   uint32_t equalStructs, samePointerStructs; // Not used, actually.
   nsChangeHint childHint = aChildFrame->StyleContext()->CalcStyleDifference(
     newContext,
     NS_HintsNotHandledForDescendantsIn(aHintForThisFrame),
     &equalStructs,
     &samePointerStructs);
   if (childHint) {
+    if (childHint & nsChangeHint_ReconstructFrame) {
+      // If we generate a reconstruct here, remove any non-reconstruct hints we
+      // may have already generated for this content.
+      aChangeList.PopChangesForContent(aChildFrame->GetContent());
+    }
     aChangeList.AppendChange(aChildFrame, aChildFrame->GetContent(), childHint);
   }
 
   for (nsIFrame* kid = aChildFrame; kid; kid = kid->GetNextContinuation()) {
     kid->SetStyleContext(newContext);
   }
 
   // Now that we've updated the style on aChildFrame, check whether it itself