Bug 1324619 part 5. Implement FrameForPseudoElement for ::first-line. r=emilio
authorBoris Zbarsky <bzbarsky@mit.edu>
Fri, 28 Jul 2017 21:20:46 -0400
changeset 420511 64f8d20599985cf1fd1fd8f5a25b60c6985506d8
parent 420510 e1b802894f33d9cfa36dfeb4dd7aa1b769e76f89
child 420512 ab3c85d4d199c903f6359e276def141d67a000d7
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)
reviewersemilio
bugs1324619
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 1324619 part 5. Implement FrameForPseudoElement for ::first-line. r=emilio MozReview-Commit-ID: JXcV58peI7T
layout/base/ServoRestyleManager.cpp
layout/generic/nsBlockFrame.cpp
layout/generic/nsBlockFrame.h
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -338,20 +338,20 @@ private:
   ServoStyleContext& mParentContext;
   ServoRestyleState& mParentRestyleState;
   RefPtr<nsStyleContext> mStyle;
   bool mShouldPostHints;
   bool mShouldComputeHints;
   nsChangeHint mComputedHint;
 };
 
-// Find the first-letter frame for the given element, if any.  Returns null to
-// indicate there isn't one.
-static nsIFrame*
-FindFirstLetterFrameForElement(const Element* aElement)
+// Get the nsBlockFrame which might contain ::first-letter/::first-line for the
+// given element.  Will return null if there is no such blockframe.
+static nsBlockFrame*
+GetBlockForElement(const Element* aElement)
 {
   nsIFrame* frame = aElement->GetPrimaryFrame();
   if (!frame) {
     return nullptr;
   }
   // The first-letter frame will always be inside the content insertion frame,
   // which will always be a block if we have a first-letter frame at all.
   frame = frame->GetContentInsertionFrame();
@@ -359,17 +359,35 @@ FindFirstLetterFrameForElement(const Ele
     // We're a leaf; certainly no first-letter frame.
     return nullptr;
   }
 
   if (!frame->IsFrameOfType(nsIFrame::eBlockFrame)) {
     return nullptr;
   }
 
-  return static_cast<nsBlockFrame*>(frame)->GetFirstLetter();
+  return static_cast<nsBlockFrame*>(frame);
+}
+
+// Find the first-letter frame for the given element, if any.  Returns null to
+// indicate there isn't one.
+static nsIFrame*
+FindFirstLetterFrameForElement(const Element* aElement)
+{
+  nsBlockFrame* f = GetBlockForElement(aElement);
+  return f ? f->GetFirstLetter() : nullptr;
+}
+
+// Find the first-line frame for the given element, if any.  Returns null to
+// indicate there isn't one.
+static nsIFrame*
+FindFirstLineFrameForElement(const Element* aElement)
+{
+  nsBlockFrame* f = GetBlockForElement(aElement);
+  return f ? f->GetFirstLineFrame() : nullptr;
 }
 
 static void
 UpdateBackdropIfNeeded(nsIFrame* aFrame,
                        ServoStyleSet& aStyleSet,
                        nsStyleChangeList& aChangeList)
 {
   const nsStyleDisplay* display = aFrame->StyleContext()->StyleDisplay();
@@ -798,18 +816,17 @@ ServoRestyleManager::FrameForPseudoEleme
     return pseudoElement ? nsLayoutUtils::GetStyleFrame(pseudoElement) : nullptr;
   }
 
   if (aPseudoTagOrNull == nsCSSPseudoElements::firstLetter) {
     return FindFirstLetterFrameForElement(aElement);
   }
 
   if (aPseudoTagOrNull == nsCSSPseudoElements::firstLine) {
-    // TODO(emilio, bz): Figure out the best way to diff these styles.
-    return nullptr;
+    return FindFirstLineFrameForElement(aElement);
   }
 
   MOZ_CRASH("Unkown pseudo-element given to "
             "ServoRestyleManager::FrameForPseudoElement");
   return nullptr;
 }
 
 void
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -7597,16 +7597,36 @@ nsBlockFrame::GetFirstLetter() const
   if (!(GetStateBits() & NS_BLOCK_HAS_FIRST_LETTER_STYLE)) {
     // Certainly no first-letter frame.
     return nullptr;
   }
 
   return GetProperty(FirstLetterProperty());
 }
 
+nsIFrame*
+nsBlockFrame::GetFirstLineFrame() const
+{
+  // Our ::first-line frame is either the first thing on our principal child
+  // list, or the second one if we have an inside bullet.
+  nsIFrame* bullet = GetInsideBullet();
+  nsIFrame* maybeFirstLine;
+  if (bullet) {
+    maybeFirstLine = bullet->GetNextSibling();
+  } else {
+    maybeFirstLine = PrincipalChildList().FirstChild();
+  }
+
+  if (maybeFirstLine && maybeFirstLine->IsLineFrame()) {
+    return maybeFirstLine;
+  }
+
+  return nullptr;
+}
+
 #ifdef DEBUG
 void
 nsBlockFrame::VerifyLines(bool aFinalCheckOK)
 {
   if (!gVerifyLines) {
     return;
   }
   if (mLines.empty()) {
--- a/layout/generic/nsBlockFrame.h
+++ b/layout/generic/nsBlockFrame.h
@@ -272,16 +272,21 @@ public:
     return outside ? outside : GetInsideBullet();
   }
 
   /**
    * @return the first-letter frame or nullptr if we don't have one.
    */
   nsIFrame* GetFirstLetter() const;
 
+  /**
+   * @return the ::first-line frame or nullptr if we don't have one.
+   */
+  nsIFrame* GetFirstLineFrame() const;
+
   void MarkIntrinsicISizesDirty() override;
 private:
   void CheckIntrinsicCacheAgainstShrinkWrapState();
 public:
   nscoord GetMinISize(gfxContext *aRenderingContext) override;
   nscoord GetPrefISize(gfxContext *aRenderingContext) override;
 
   nsRect ComputeTightBounds(DrawTarget* aDrawTarget) const override;