Bug 1366721: Restyle additional style contexts in ServoRestyleManager. r?heycam draft
authorEmilio Cobos Álvarez <emilio@crisal.io>
Thu, 20 Jul 2017 18:29:14 +0200
changeset 613077 5e235f59cfa551bbfdb85d32406b1cc7a1a10e4e
parent 613071 ef5d75ab4d8bc97cdc1020a924ee39a44cc9a23c
child 613078 fb06233940bb2b86aa2f6e96794317ca36e5182d
push id69721
push userbmo:emilio+bugs@crisal.io
push dateFri, 21 Jul 2017 14:44:52 +0000
reviewersheycam
bugs1366721
milestone56.0a1
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)