Bug 1324619 part 6. Handle dynamic restyles of ::first-line in stylo. r?emilio draft
authorBoris Zbarsky <bzbarsky@mit.edu>
Fri, 28 Jul 2017 21:20:47 -0400
changeset 617971 31ad3df05bc4b20fb54dfc6eeadf556210cb63f0
parent 617970 1cb14620b1725e09b8892ea23889a986b6a72cd5
child 639920 173d516f2fbcad57c98369f5a9de8dba34ae443c
push id71168
push userbzbarsky@mozilla.com
push dateSat, 29 Jul 2017 01:21:16 +0000
reviewersemilio
bugs1324619
milestone56.0a1
Bug 1324619 part 6. Handle dynamic restyles of ::first-line in stylo. r?emilio MozReview-Commit-ID: 3jQhIqPuL1g
layout/base/ServoRestyleManager.cpp
layout/generic/nsBlockFrame.cpp
layout/reftests/bugs/reftest.list
layout/reftests/first-line/reftest.list
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -53,16 +53,26 @@ ExpectedOwnerForChild(const nsIFrame& aF
   if (IsAnonBox(aFrame) && !aFrame.IsTextFrame()) {
     return aFrame.GetParent()->IsViewportFrame() ? nullptr : aFrame.GetParent();
   }
 
   if (aFrame.IsBulletFrame()) {
     return aFrame.GetParent();
   }
 
+  if (aFrame.IsLineFrame()) {
+    // A ::first-line always ends up here via its block, which is therefore the
+    // right expected owner.  That block can be an
+    // anonymous box.  For example, we could have a ::first-line on a columnated
+    // block; the blockframe is the column-content anonymous box in that case.
+    // So we don't want to end up in the code below, which steps out of anon
+    // boxes.  Just return the parent of the line frame, which is the block.
+    return aFrame.GetParent();
+  }
+
   const nsIFrame* parent = FirstContinuationOrPartOfIBSplit(aFrame.GetParent());
 
   if (aFrame.IsTableFrame()) {
     MOZ_ASSERT(parent->IsTableWrapperFrame());
     parent = FirstContinuationOrPartOfIBSplit(parent->GetParent());
   }
 
   // We've handled already anon boxes and bullet frames, so now we're looking at
@@ -706,18 +716,40 @@ ServoRestyleManager::ProcessPostTraversa
       }
     }
   }
 
   // We want to update frame pseudo-element styles after we've traversed our
   // kids, because some of those updates (::first-line/::first-letter) need to
   // modify the styles of the kids, and the child traversal above would just
   // clobber those modifications.
-  if (wasRestyled && styleFrame) {
-    UpdateFramePseudoElementStyles(styleFrame, childrenRestyleState);
+  if (styleFrame) {
+    if (wasRestyled) {
+      UpdateFramePseudoElementStyles(styleFrame, childrenRestyleState);
+    } else if (traverseElementChildren &&
+               styleFrame->IsFrameOfType(nsIFrame::eBlockFrame)) {
+      // Even if we were not restyled, if we're a block with a first-line and
+      // one of our descendant elements which is on the first line was restyled,
+      // we need to update the styles of things on the first line, because
+      // they're wrong now.
+      //
+      // FIXME(bz) Could we do better here?  For example, could we keep track of
+      // frames that are "block with a ::first-line so we could avoid
+      // IsFrameOfType() and digging about for the first-line frame if not?
+      // Could we keep track of whether the element children we actually restyle
+      // are affected by first-line?  Something else?  Bug 1385443 tracks making
+      // this better.
+      nsIFrame* firstLineFrame =
+        static_cast<nsBlockFrame*>(styleFrame)->GetFirstLineFrame();
+      if (firstLineFrame) {
+        for (nsIFrame* kid : firstLineFrame->PrincipalChildList()) {
+          ReparentStyleContext(kid);
+        }
+      }
+    }
   }
 
   if (!forThrottledAnimationFlush) {
     aElement->UnsetHasDirtyDescendantsForServo();
     aElement->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES);
   }
   aElement->UnsetHasAnimationOnlyDirtyDescendantsForServo();
   return recreatedAnyContext;
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -7571,16 +7571,47 @@ void
 nsBlockFrame::UpdatePseudoElementStyles(ServoRestyleState& aRestyleState)
 {
   if (nsBulletFrame* bullet = GetBullet()) {
     CSSPseudoElementType type = bullet->StyleContext()->GetPseudoType();
     RefPtr<nsStyleContext> newBulletStyle =
       ResolveBulletStyle(type, &aRestyleState.StyleSet());
     UpdateStyleOfOwnedChildFrame(bullet, newBulletStyle, aRestyleState);
   }
+
+  if (nsIFrame* firstLineFrame = GetFirstLineFrame()) {
+    nsIFrame* styleParent =
+      CorrectStyleParentFrame(firstLineFrame->GetParent(),
+                              nsCSSPseudoElements::firstLine);
+
+    ServoStyleContext* parentStyle = styleParent->StyleContext()->AsServo();
+    RefPtr<ServoStyleContext> firstLineStyle =
+      aRestyleState.StyleSet()
+                   .ResolvePseudoElementStyle(mContent->AsElement(),
+                                              CSSPseudoElementType::firstLine,
+                                              parentStyle,
+                                              nullptr);
+
+    // FIXME(bz): Can we make first-line continuations be non-inheriting anon
+    // boxes?
+    RefPtr<ServoStyleContext> continuationStyle = aRestyleState.StyleSet().
+      ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::mozLineFrame,
+                                         parentStyle);
+
+    UpdateStyleOfOwnedChildFrame(firstLineFrame, firstLineStyle, aRestyleState,
+                                 Some(continuationStyle.get()));
+
+    // We also want to update the styles of the first-line's descendants.  We
+    // don't need to compute a changehint for this, though, since any changes to
+    // them are handled by the first-line anyway.
+    ServoRestyleManager* manager = PresContext()->RestyleManager()->AsServo();
+    for (nsIFrame* kid : firstLineFrame->PrincipalChildList()) {
+      manager->ReparentStyleContext(kid);
+    }
+  }
 }
 
 already_AddRefed<nsStyleContext>
 nsBlockFrame::ResolveBulletStyle(CSSPseudoElementType aType,
                                  StyleSetHandle aStyleSet)
 {
   nsStyleContext* parentStyle =
     CorrectStyleParentFrame(this,
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1691,17 +1691,17 @@ fuzzy-if(skiaContent,1,3500) == 660682-1
 fuzzy-if(d2d,1,256) skip-if(Android) fuzzy-if(skiaContent,1,68000) == 664127-1.xul 664127-1-ref.xul # Android: Intermittent failures - bug 1019131
 == 665597-1.html 665597-1-ref.html
 == 665597-2.html 665597-2-ref.html
 == 667079-1.html 667079-1-ref.html
 == 668319-1.xul about:blank
 != 669015-1.xul 669015-1-notref.xul
 skip-if(azureSkiaGL) == 670442-1.html 670442-1-ref.html
 == 670467-1.html 670467-1-ref.html
-fails-if(styloVsGecko||stylo) == 670467-2.html 670467-2-ref.html
+== 670467-2.html 670467-2-ref.html
 == 690164-1.html 690164-1-ref.html
 == 690643-1.html 690643-1-ref.html
 != 691087-1.html 691087-1-ref.html
 == 691571-1.html 691571-1-ref.html
 fuzzy-if(skiaContent,1,200) == 696307-1.html 696307-1-ref.html
 fuzzy-if(skiaContent,1,550) == 696739-1.html 696739-1-ref.html
 needs-focus == 703186-1.html 703186-1-ref.html
 needs-focus == 703186-2.html 703186-2-ref.html
--- a/layout/reftests/first-line/reftest.list
+++ b/layout/reftests/first-line/reftest.list
@@ -27,15 +27,15 @@ load stress-10.html # crash test
 
 == border-not-apply.html border-not-apply-ref.html
 == 287088-1.html 287088-1-ref.html
 == 287088-2.html 287088-2-ref.html
 == 403177-1.html 403177-1-ref.html
 == 469227-2.html 469227-2-ref.html
 == 469227-3.html 469227-3-ref.html
 
-fails-if(styloVsGecko||stylo) == restyle-inside-first-line.html restyle-inside-first-line-ref.html
+== restyle-inside-first-line.html restyle-inside-first-line-ref.html
 == font-styles.html font-styles-ref.html
 fuzzy-if(OSX==1010,1,2) == font-styles-nooverflow.html font-styles-ref.html
 
 fails-if(!stylo) == ib-split-1.html ib-split-1-ref.html
 
 == first-line-in-columnset-1.html first-line-in-columnset-1-ref.html