Bug 947158 - Implement DrainSelfOverflowList for nsInlineFrame and nsFirstLineFrame. r=bz

This commit is contained in:
Mats Palmgren 2013-12-17 13:30:24 +00:00
parent 0cf0347d66
commit 8882c5de34
2 changed files with 88 additions and 32 deletions

View File

@ -368,29 +368,12 @@ nsInlineFrame::Reflow(nsPresContext* aPresContext,
}
#endif
if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
AutoFrameListPtr overflowFrames(aPresContext, StealOverflowFrames());
if (overflowFrames) {
NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames");
if (!lazilySetParentPointer) {
// The frames on our own overflowlist may have been pushed by a
// previous lazilySetParentPointer Reflow so we need to ensure
// the correct parent pointer now since we're not setting it
// lazily in this Reflow.
nsIFrame* firstChild = overflowFrames->FirstChild();
if (lineContainer && lineContainer->GetPrevContinuation()) {
ReparentFloatsForInlineChild(lineContainer, firstChild, true);
}
const bool inFirstLine = aReflowState.mLineLayout->GetInFirstLine();
RestyleManager* restyleManager = PresContext()->RestyleManager();
for (nsIFrame* f = firstChild; f; f = f->GetNextSibling()) {
f->SetParent(this);
if (inFirstLine) {
restyleManager->ReparentStyleContext(f);
}
}
}
mFrames.AppendFrames(nullptr, *overflowFrames);
DrainFlags flags =
lazilySetParentPointer ? eDontReparentFrames : DrainFlags(0);
if (aReflowState.mLineLayout->GetInFirstLine()) {
flags = DrainFlags(flags | eInFirstLine);
}
DrainSelfOverflowListInternal(flags, lineContainer);
}
// Set our own reflow state (additional state above and beyond
@ -421,6 +404,53 @@ nsInlineFrame::Reflow(nsPresContext* aPresContext,
return rv;
}
bool
nsInlineFrame::DrainSelfOverflowListInternal(DrainFlags aFlags,
nsIFrame* aLineContainer)
{
AutoFrameListPtr overflowFrames(PresContext(), StealOverflowFrames());
if (overflowFrames) {
NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames");
// The frames on our own overflowlist may have been pushed by a
// previous lazilySetParentPointer Reflow so we need to ensure the
// correct parent pointer. This is sometimes skipped by Reflow.
if (!(aFlags & eDontReparentFrames)) {
nsIFrame* firstChild = overflowFrames->FirstChild();
if (aLineContainer && aLineContainer->GetPrevContinuation()) {
ReparentFloatsForInlineChild(aLineContainer, firstChild, true);
}
const bool inFirstLine = (aFlags & eInFirstLine);
RestyleManager* restyleManager = PresContext()->RestyleManager();
for (nsIFrame* f = firstChild; f; f = f->GetNextSibling()) {
f->SetParent(this);
if (inFirstLine) {
restyleManager->ReparentStyleContext(f);
}
}
}
bool result = !overflowFrames->IsEmpty();
mFrames.AppendFrames(nullptr, *overflowFrames);
return result;
}
return false;
}
/* virtual */ bool
nsInlineFrame::DrainSelfOverflowList()
{
nsIFrame* lineContainer = nsLayoutUtils::FindNearestBlockAncestor(this);
// Add the eInFirstLine flag if we have a ::first-line ancestor frame.
// No need to look further than the nearest line container though.
DrainFlags flags = DrainFlags(0);
for (nsIFrame* p = GetParent(); p != lineContainer; p = p->GetParent()) {
if (p->GetType() == nsGkAtoms::lineFrame) {
flags = DrainFlags(flags | eInFirstLine);
break;
}
}
return DrainSelfOverflowListInternal(flags, lineContainer);
}
/* virtual */ bool
nsInlineFrame::CanContinueTextRun() const
{
@ -1018,15 +1048,8 @@ nsFirstLineFrame::Reflow(nsPresContext* aPresContext,
}
}
// It's also possible that we have an overflow list for ourselves
AutoFrameListPtr overflowFrames(aPresContext, StealOverflowFrames());
if (overflowFrames) {
NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames");
const nsFrameList::Slice& newFrames =
mFrames.AppendFrames(nullptr, *overflowFrames);
ReparentChildListStyle(aPresContext, newFrames, this);
}
// It's also possible that we have an overflow list for ourselves.
DrainSelfOverflowList();
// Set our own reflow state (additional state above and beyond
// aReflowState)
@ -1094,3 +1117,18 @@ nsFirstLineFrame::PullOverflowsFromPrevInFlow()
}
}
/* virtual */ bool
nsFirstLineFrame::DrainSelfOverflowList()
{
AutoFrameListPtr overflowFrames(PresContext(), StealOverflowFrames());
if (overflowFrames) {
NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames");
bool result = !overflowFrames->IsEmpty();
const nsFrameList::Slice& newFrames =
mFrames.AppendFrames(nullptr, *overflowFrames);
ReparentChildListStyle(PresContext(), newFrames, this);
return result;
}
return false;
}

View File

@ -92,6 +92,7 @@ public:
virtual void PullOverflowsFromPrevInFlow() MOZ_OVERRIDE;
virtual nscoord GetBaseline() const MOZ_OVERRIDE;
virtual bool DrainSelfOverflowList() MOZ_OVERRIDE;
/**
* Return true if the frame is leftmost frame or continuation.
@ -168,6 +169,22 @@ protected:
nsIFrame* aPrevSibling,
InlineReflowState& aState);
private:
// Helper method for DrainSelfOverflowList() to deal with lazy parenting
// (which we only do for nsInlineFrame, not nsFirstLineFrame).
enum DrainFlags {
eDontReparentFrames = 1, // skip reparenting the overflow list frames
eInFirstLine = 2, // the request is for an inline descendant of a nsFirstLineFrame
};
/**
* Move any frames on our overflow list to the end of our principal list.
* @param aFlags one or more of the above DrainFlags
* @param aLineContainer the nearest line container ancestor
* @return true if there were any overflow frames
*/
bool DrainSelfOverflowListInternal(DrainFlags aFlags,
nsIFrame* aLineContainer);
protected:
nscoord mBaseline;
};
@ -177,7 +194,7 @@ protected:
* Variation on inline-frame used to manage lines for line layout in
* special situations (:first-line style in particular).
*/
class nsFirstLineFrame : public nsInlineFrame {
class nsFirstLineFrame MOZ_FINAL : public nsInlineFrame {
public:
NS_DECL_FRAMEARENA_HELPERS
@ -195,6 +212,7 @@ public:
virtual void Init(nsIContent* aContent, nsIFrame* aParent,
nsIFrame* aPrevInFlow) MOZ_OVERRIDE;
virtual void PullOverflowsFromPrevInFlow() MOZ_OVERRIDE;
virtual bool DrainSelfOverflowList() MOZ_OVERRIDE;
protected:
nsFirstLineFrame(nsStyleContext* aContext) : nsInlineFrame(aContext) {}