Bug 1366721: Restyle additional style contexts in ServoRestyleManager. r=heycam
authorEmilio Cobos Álvarez <emilio@crisal.io>
Thu, 20 Jul 2017 18:29:14 +0200
changeset 418879 346f57883936defca24432a7163bcbe8ebfe1362
parent 418878 6ce98d80d88266a9831cbab430afbb5a8f101ae8
child 418880 e7c0f783e4fcb11444c248e673a52fb45e22c433
push id7566
push usermtabara@mozilla.com
push dateWed, 02 Aug 2017 08:25:16 +0000
treeherdermozilla-beta@86913f512c3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs1366721
milestone56.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 1366721: Restyle additional style contexts in ServoRestyleManager. r=heycam I was about to assert that other non-primary frames don't have additional style contexts everywhere, but that wouldn't make much sense, given they don't correspond to an element we could selector-match against. MozReview-Commit-ID: EtAQbSg6nP6
layout/base/ServoRestyleManager.cpp
layout/generic/nsFrame.cpp
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -418,16 +418,68 @@ UpdateFirstLetterIfNeeded(nsIFrame* aFra
   while (!block->IsFrameOfType(nsIFrame::eBlockFrame)) {
     block = block->GetParent();
   }
   static_cast<nsBlockFrame*>(block->FirstContinuation())->
     UpdateFirstLetterStyle(aRestyleState);
 }
 
 static void
+UpdateOneAdditionalStyleContext(nsIFrame* aFrame,
+                                uint32_t aIndex,
+                                ServoStyleContext& aOldContext,
+                                ServoRestyleState& aRestyleState)
+{
+  auto pseudoType = aOldContext.GetPseudoType();
+  MOZ_ASSERT(pseudoType != CSSPseudoElementType::NotPseudo);
+  MOZ_ASSERT(
+      !nsCSSPseudoElements::PseudoElementSupportsUserActionState(pseudoType));
+
+  RefPtr<ServoStyleContext> newContext =
+    aRestyleState.StyleSet().ResolvePseudoElementStyle(
+        aFrame->GetContent()->AsElement(),
+        pseudoType,
+        aFrame->StyleContext()->AsServo(),
+        /* aPseudoElement = */ nullptr);
+
+  uint32_t equalStructs, samePointerStructs; // Not used, actually.
+  nsChangeHint childHint = aOldContext.CalcStyleDifference(
+    newContext,
+    &equalStructs,
+    &samePointerStructs);
+  if (!aFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
+    childHint = NS_RemoveSubsumedHints(
+        childHint, aRestyleState.ChangesHandledFor(*aFrame));
+  }
+
+  if (childHint) {
+    aRestyleState.ChangeList().AppendChange(
+        aFrame, aFrame->GetContent(), childHint);
+  }
+
+  aFrame->SetAdditionalStyleContext(aIndex, newContext);
+}
+
+static void
+UpdateAdditionalStyleContexts(nsIFrame* aFrame,
+                              ServoRestyleState& aRestyleState)
+{
+  MOZ_ASSERT(aFrame);
+  MOZ_ASSERT(aFrame->GetContent() && aFrame->GetContent()->IsElement());
+
+  // FIXME(emilio): Consider adding a bit or something to avoid the initial
+  // virtual call?
+  uint32_t index = 0;
+  while (auto* oldContext = aFrame->GetAdditionalStyleContext(index)) {
+    UpdateOneAdditionalStyleContext(
+        aFrame, index++, *oldContext->AsServo(), aRestyleState);
+  }
+}
+
+static void
 UpdateFramePseudoElementStyles(nsIFrame* aFrame,
                                ServoRestyleState& aRestyleState)
 {
   // first-letter needs to be updated before first-line, because first-line can
   // change the style of the first-letter.
   UpdateFirstLetterIfNeeded(aFrame, aRestyleState);
 
   if (aFrame->IsFrameOfType(nsIFrame::eBlockFrame)) {
@@ -566,25 +618,27 @@ ServoRestyleManager::ProcessPostTraversa
     // styles).  But in that case, newContext is the right context for the
     // _later_ continuations anyway (the ones not affected by ::first-line), not
     // the earlier ones, so there is no point stopping right at the point when
     // we'd actually be setting the right style context.
     //
     // This does mean that we may be setting the wrong style context on our
     // initial continuations; ::first-line fixes that up after the fact.
     for (nsIFrame* f = styleFrame; f; f = f->GetNextContinuation()) {
+      MOZ_ASSERT_IF(f != styleFrame, !f->GetAdditionalStyleContext(0));
       f->SetStyleContext(newContext);
     }
 
     if (MOZ_UNLIKELY(displayContentsNode)) {
       MOZ_ASSERT(!styleFrame);
       displayContentsNode->mStyle = newContext;
     }
 
     if (styleFrame) {
+      UpdateAdditionalStyleContexts(styleFrame, aRestyleState);
       styleFrame->UpdateStyleOfOwnedAnonBoxes(childrenRestyleState);
     }
 
     if (!aElement->GetParent()) {
       // This is the root.  Update styles on the viewport as needed.
       ViewportFrame* viewport =
         do_QueryFrame(mPresContext->PresShell()->GetRootFrame());
       if (viewport) {
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -10252,16 +10252,19 @@ nsIFrame::UpdateStyleOfChildAnonBox(nsIF
 
 /* static */ nsChangeHint
 nsIFrame::UpdateStyleOfOwnedChildFrame(
   nsIFrame* aChildFrame,
   nsStyleContext* aNewStyleContext,
   ServoRestyleState& aRestyleState,
   const Maybe<nsStyleContext*>& aContinuationStyleContext)
 {
+  MOZ_ASSERT(!aChildFrame->GetAdditionalStyleContext(0),
+             "We don't handle additional style contexts here");
+
   // Figure out whether we have an actual change.  It's important that we do
   // this, for several reasons:
   //
   // 1) Even if all the child's changes are due to properties it inherits from
   //    us, it's possible that no one ever asked us for those style structs and
   //    hence changes to them aren't reflected in the changes handled at all.
   //
   // 2) Content can change stylesheets that change the styles of pseudos, and
@@ -10299,16 +10302,17 @@ nsIFrame::UpdateStyleOfOwnedChildFrame(
   }
 
   aChildFrame->SetStyleContext(aNewStyleContext);
   nsStyleContext* continuationStyle =
     aContinuationStyleContext ? *aContinuationStyleContext : aNewStyleContext;
   for (nsIFrame* kid = aChildFrame->GetNextContinuation();
        kid;
        kid = kid->GetNextContinuation()) {
+    MOZ_ASSERT(!kid->GetAdditionalStyleContext(0));
     kid->SetStyleContext(continuationStyle);
   }
 
   return childHint;
 }
 
 /* static */ void
 nsIFrame::AddInPopupStateBitToDescendants(nsIFrame* aFrame)