Bug 1324618 part 4. Implement a way to get the first-letter frame, if any, for a block. r?heycam
MozReview-Commit-ID: 1o0d5ugJ1hj
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -11625,17 +11625,17 @@ static bool IsFirstLetterContent(nsICont
{
return aContent->TextLength() &&
!aContent->TextIsOnlyWhitespace();
}
/**
* Create a letter frame, only make it a floating frame.
*/
-void
+nsFirstLetterFrame*
nsCSSFrameConstructor::CreateFloatingLetterFrame(
nsFrameConstructorState& aState,
nsIContent* aTextContent,
nsIFrame* aTextFrame,
nsContainerFrame* aParentFrame,
nsStyleContext* aStyleContext,
nsFrameItems& aResult)
{
@@ -11690,16 +11690,18 @@ nsCSSFrameConstructor::CreateFloatingLet
aState.AddChild(letterFrame, aResult, letterContent, aStyleContext,
aParentFrame, false, true, false, true,
link.PrevFrame());
if (nextTextFrame) {
aResult.AddChild(nextTextFrame);
}
+
+ return letterFrame;
}
/**
* Create a new letter frame for aTextFrame. The letter frame will be
* a child of aParentFrame.
*/
void
nsCSSFrameConstructor::CreateLetterFrame(nsContainerFrame* aBlockFrame,
@@ -11746,41 +11748,46 @@ nsCSSFrameConstructor::CreateLetterFrame
nsFrameConstructorState state(mPresShell,
matchContext,
GetAbsoluteContainingBlock(aParentFrame, FIXED_POS),
GetAbsoluteContainingBlock(aParentFrame, ABS_POS),
aBlockContinuation);
// Create the right type of first-letter frame
const nsStyleDisplay* display = sc->StyleDisplay();
+ nsFirstLetterFrame* letterFrame;
if (display->IsFloatingStyle() &&
!nsSVGUtils::IsInSVGTextSubtree(aParentFrame)) {
// Make a floating first-letter frame
- CreateFloatingLetterFrame(state, aTextContent, textFrame,
- aParentFrame, sc, aResult);
+ letterFrame = CreateFloatingLetterFrame(state, aTextContent, textFrame,
+ aParentFrame, sc, aResult);
}
else {
// Make an inflow first-letter frame
- nsFirstLetterFrame* letterFrame = NS_NewFirstLetterFrame(mPresShell, sc);
+ letterFrame = NS_NewFirstLetterFrame(mPresShell, sc);
// Initialize the first-letter-frame. We don't want to use a text
// content for a non-text frame (because we want its primary frame to
// be a text frame). So use its parent for the first-letter.
nsIContent* letterContent = aTextContent->GetParent();
letterFrame->Init(letterContent, aParentFrame, nullptr);
InitAndRestoreFrame(state, aTextContent, letterFrame, textFrame);
SetInitialSingleChild(letterFrame, textFrame);
aResult.Clear();
aResult.AddChild(letterFrame);
NS_ASSERTION(!aBlockFrame->GetPrevContinuation(),
"should have the first continuation here");
aBlockFrame->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_CHILD);
}
+ MOZ_ASSERT(!aBlockFrame->GetPrevContinuation(),
+ "Setting up a first-letter frame on a non-first block continuation?");
+ aBlockFrame->SetProperty(nsContainerFrame::FirstLetterProperty(),
+ letterFrame);
aTextContent->SetPrimaryFrame(textFrame);
}
}
void
nsCSSFrameConstructor::WrapFramesInFirstLetterFrame(
nsContainerFrame* aBlockFrame,
nsFrameItems& aBlockFrames)
@@ -12047,16 +12054,17 @@ nsCSSFrameConstructor::RemoveFirstLetter
}
void
nsCSSFrameConstructor::RemoveLetterFrames(nsIPresShell* aPresShell,
nsContainerFrame* aBlockFrame)
{
aBlockFrame =
static_cast<nsContainerFrame*>(aBlockFrame->FirstContinuation());
+ aBlockFrame->RemoveProperty(nsContainerFrame::FirstLetterProperty());
nsContainerFrame* continuation = aBlockFrame;
bool stopLooking = false;
do {
RemoveFloatingFirstLetterFrames(aPresShell, continuation);
RemoveFirstLetterFrames(aPresShell, continuation, aBlockFrame,
&stopLooking);
if (stopLooking) {
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -26,16 +26,17 @@
struct nsFrameItems;
class nsStyleContext;
struct nsStyleDisplay;
struct nsGenConInitializer;
class nsContainerFrame;
class nsFirstLineFrame;
+class nsFirstLetterFrame;
class nsICSSAnonBoxPseudo;
class nsIDocument;
class nsPageContentFrame;
struct PendingBinding;
class nsGenericDOMDataNode;
class nsFrameConstructorState;
@@ -1938,22 +1939,23 @@ private:
void ReframeContainingBlock(nsIFrame* aFrame,
RemoveFlags aFlags,
nsIContent** aReframeContent);
//----------------------------------------
// Methods support :first-letter style
- void CreateFloatingLetterFrame(nsFrameConstructorState& aState,
- nsIContent* aTextContent,
- nsIFrame* aTextFrame,
- nsContainerFrame* aParentFrame,
- nsStyleContext* aStyleContext,
- nsFrameItems& aResult);
+ nsFirstLetterFrame*
+ CreateFloatingLetterFrame(nsFrameConstructorState& aState,
+ nsIContent* aTextContent,
+ nsIFrame* aTextFrame,
+ nsContainerFrame* aParentFrame,
+ nsStyleContext* aStyleContext,
+ nsFrameItems& aResult);
void CreateLetterFrame(nsContainerFrame* aBlockFrame,
nsContainerFrame* aBlockContinuation,
nsIContent* aTextContent,
nsContainerFrame* aParentFrame,
nsFrameItems& aResult);
void WrapFramesInFirstLetterFrame(nsContainerFrame* aBlockFrame,
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -7534,16 +7534,27 @@ nsBlockFrame::ResolveBulletStyle(CSSPseu
CorrectStyleParentFrame(this,
nsCSSPseudoElements::GetPseudoAtom(aType))->
StyleContext();
return aStyleSet->ResolvePseudoElementStyle(mContent->AsElement(), aType,
parentStyle, nullptr);
}
+nsIFrame*
+nsBlockFrame::GetFirstLetter() const
+{
+ if (!(GetStateBits() & NS_BLOCK_HAS_FIRST_LETTER_STYLE)) {
+ // Certainly no first-letter frame.
+ return nullptr;
+ }
+
+ return GetProperty(FirstLetterProperty());
+}
+
#ifdef DEBUG
void
nsBlockFrame::VerifyLines(bool aFinalCheckOK)
{
if (!gVerifyLines) {
return;
}
if (mLines.empty()) {
--- a/layout/generic/nsBlockFrame.h
+++ b/layout/generic/nsBlockFrame.h
@@ -267,16 +267,21 @@ public:
/**
* @return the bullet frame or nullptr if we don't have one.
*/
nsBulletFrame* GetBullet() const {
nsBulletFrame* outside = GetOutsideBullet();
return outside ? outside : GetInsideBullet();
}
+ /**
+ * @return the first-letter frame or nullptr if we don't have one.
+ */
+ nsIFrame* GetFirstLetter() const;
+
void MarkIntrinsicISizesDirty() override;
private:
void CheckIntrinsicCacheAgainstShrinkWrapState();
public:
nscoord GetMinISize(gfxContext *aRenderingContext) override;
nscoord GetPrefISize(gfxContext *aRenderingContext) override;
nsRect ComputeTightBounds(DrawTarget* aDrawTarget) const override;
--- a/layout/generic/nsContainerFrame.h
+++ b/layout/generic/nsContainerFrame.h
@@ -516,16 +516,20 @@ public:
typedef PropertyDescriptor<nsFrameList> FrameListPropertyDescriptor;
NS_DECLARE_FRAME_PROPERTY_FRAMELIST(OverflowProperty)
NS_DECLARE_FRAME_PROPERTY_FRAMELIST(OverflowContainersProperty)
NS_DECLARE_FRAME_PROPERTY_FRAMELIST(ExcessOverflowContainersProperty)
NS_DECLARE_FRAME_PROPERTY_FRAMELIST(BackdropProperty)
+ // Only really used on nsBlockFrame instances, but the caller thinks it could
+ // have arbitrary nsContainerFrames.
+ NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(FirstLetterProperty, nsIFrame)
+
#ifdef DEBUG
// Use this to suppress the CRAZY_SIZE assertions.
NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(DebugReflowingWithInfiniteISize, bool)
bool IsCrazySizeAssertSuppressed() const {
return GetProperty(DebugReflowingWithInfiniteISize());
}
#endif