Bug 1324618 part 8. Implement restyling for first-letter frames. r?emilio draft
authorBoris Zbarsky <bzbarsky@mit.edu>
Mon, 26 Jun 2017 23:35:08 -0700
changeset 600505 410f00b19f805bcbe83101252311b7e16986a56d
parent 600504 933c8d807ca43911df37368f6eca0f166a118c7b
child 600506 8c38971cfbdcb6d0c0fea8b56da16e62ad4cbfbb
push id65783
push userbzbarsky@mozilla.com
push dateTue, 27 Jun 2017 06:35:27 +0000
reviewersemilio
bugs1324618
milestone56.0a1
Bug 1324618 part 8. Implement restyling for first-letter frames. r?emilio MozReview-Commit-ID: IPUDD1Q6AFq
layout/base/nsCSSFrameConstructor.cpp
layout/generic/nsBlockFrame.cpp
layout/generic/nsBlockFrame.h
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -11710,17 +11710,18 @@ nsCSSFrameConstructor::CreateLetterFrame
                                          nsContainerFrame* aParentFrame,
                                          nsFrameItems& aResult)
 {
   NS_PRECONDITION(aTextContent->IsNodeOfType(nsINode::eTEXT),
                   "aTextContent isn't text");
   NS_ASSERTION(nsLayoutUtils::GetAsBlock(aBlockFrame),
                  "Not a block frame?");
 
-  // Get style context for the first-letter-frame
+  // Get style context for the first-letter-frame.  Keep this in sync with
+  // nsBlockFrame::UpdatePseudoElementStyles.
   nsStyleContext* parentStyleContext =
     nsFrame::CorrectStyleParentFrame(aParentFrame,
                                      nsCSSPseudoElements::firstLetter)->
       StyleContext();
 
   // Use content from containing block so that we can actually
   // find a matching style rule.
   nsIContent* blockContent = aBlockFrame->GetContent();
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -5620,16 +5620,56 @@ nsBlockInFlowLineIterator::nsBlockInFlow
 nsBlockInFlowLineIterator::nsBlockInFlowLineIterator(nsBlockFrame* aFrame,
     bool* aFoundValidLine)
   : mFrame(aFrame), mLineList(&aFrame->mLines)
 {
   mLine = aFrame->LinesBegin();
   *aFoundValidLine = FindValidLine();
 }
 
+void
+nsBlockFrame::UpdateFirstLetterStyle(nsIFrame* aLetterFrame,
+                                     ServoRestyleState& aRestyleState)
+{
+  // Figure out what the right style parent is.  This needs to match
+  // nsCSSFrameConstructor::CreateLetterFrame.
+  nsIFrame* inFlowFrame = aLetterFrame;
+  if (inFlowFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
+    inFlowFrame = inFlowFrame->GetPlaceholderFrame();
+  }
+  nsIFrame* styleParent =
+    CorrectStyleParentFrame(inFlowFrame->GetParent(),
+                            nsCSSPseudoElements::firstLetter);
+  nsStyleContext* parentStyle = styleParent->StyleContext();
+  RefPtr<nsStyleContext> firstLetterStyle =
+    aRestyleState.StyleSet()
+                 .ResolvePseudoElementStyle(mContent->AsElement(),
+                                            CSSPseudoElementType::firstLetter,
+                                            parentStyle,
+                                            nullptr);
+  // Note that we don't need to worry about changehints for the continuation
+  // styles: those will be handled by the styleParent already.
+  RefPtr<nsStyleContext> continuationStyle =
+    aRestyleState.StyleSet().ResolveStyleForFirstLetterContinuation(parentStyle);
+  UpdateStyleOfOwnedChildFrame(aLetterFrame, firstLetterStyle, aRestyleState,
+                               Some(continuationStyle.get()));
+
+  // We also want to update the style on the textframe inside the first-letter.
+  // We don't need to compute a changehint for this, though, since any changes
+  // to it are handled by the first-letter anyway.
+  nsIFrame* textFrame = aLetterFrame->PrincipalChildList().FirstChild();
+  RefPtr<nsStyleContext> firstTextStyle =
+    aRestyleState.StyleSet().ResolveStyleForText(textFrame->GetContent(),
+                                                 firstLetterStyle);
+  textFrame->SetStyleContext(firstTextStyle);
+
+  // We don't need to update style for textFrame's continuations: it's already
+  // set up to inherit from parentStyle, which is what we want.
+}
+
 static nsIFrame*
 FindChildContaining(nsBlockFrame* aFrame, nsIFrame* aFindFrame)
 {
   NS_ASSERTION(aFrame, "must have frame");
   nsIFrame* child;
   while (true) {
     nsIFrame* block = aFrame;
     do {
@@ -7519,16 +7559,20 @@ 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* firstLetter = GetFirstLetter()) {
+    UpdateFirstLetterStyle(firstLetter, aRestyleState);
+  }
 }
 
 already_AddRefed<nsStyleContext>
 nsBlockFrame::ResolveBulletStyle(CSSPseudoElementType aType,
                                  StyleSetHandle aStyleSet)
 {
   nsStyleContext* parentStyle =
     CorrectStyleParentFrame(this,
--- a/layout/generic/nsBlockFrame.h
+++ b/layout/generic/nsBlockFrame.h
@@ -918,16 +918,20 @@ protected:
 
   // Resolve a style context for our bullet frame.  aType should be
   // mozListBullet or mozListNumber.  Passing in the style set is an
   // optimization, because all callsites have it.
   already_AddRefed<nsStyleContext> ResolveBulletStyle(
     mozilla::CSSPseudoElementType aType,
     mozilla::StyleSetHandle aStyleSet);
 
+  // Update our first-letter styles during stylo post-traversal.
+  void UpdateFirstLetterStyle(nsIFrame* aLetterFrame,
+                              mozilla::ServoRestyleState& aRestyleState);
+
 #ifdef DEBUG
   void VerifyLines(bool aFinalCheckOK);
   void VerifyOverflowSituation();
   int32_t GetDepth() const;
 #endif
 
   nscoord mMinWidth, mPrefWidth;