Bug 1324619 part 5. Implement FrameForPseudoElement for ::first-line. r?emilio
MozReview-Commit-ID: JXcV58peI7T
--- 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;