mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 504221 part 10. Switch the first-line frame list munging to nsFrameList. r=fantasai, r+sr=roc
This commit is contained in:
parent
dca83c78dc
commit
cddaf1831c
@ -689,7 +689,7 @@ nsFrameItems::AddChild(nsIFrame* aChild)
|
||||
// parents (caption, I'm looking at you) on the same framelist, and
|
||||
// nsFrameList asserts if you try to do that.
|
||||
if (IsEmpty()) {
|
||||
AppendFrames(nsnull, aChild);
|
||||
nsFrameList::AppendFrames(nsnull, aChild);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -9558,7 +9558,8 @@ nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState& aState,
|
||||
rv = WrapFramesInFirstLetterFrame(aContent, aFrame, aFrameItems);
|
||||
}
|
||||
if (haveFirstLineStyle) {
|
||||
rv = WrapFramesInFirstLineFrame(aState, aContent, aFrame, aFrameItems);
|
||||
rv = WrapFramesInFirstLineFrame(aState, aContent, aFrame, nsnull,
|
||||
aFrameItems);
|
||||
}
|
||||
|
||||
// We might end up with first-line frames that change
|
||||
@ -9637,72 +9638,60 @@ nsCSSFrameConstructor::WrapFramesInFirstLineFrame(
|
||||
nsFrameConstructorState& aState,
|
||||
nsIContent* aBlockContent,
|
||||
nsIFrame* aBlockFrame,
|
||||
nsIFrame* aLineFrame,
|
||||
nsFrameItems& aFrameItems)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// Find the first and last inline frame in aFrameItems
|
||||
nsIFrame* kid = aFrameItems.FirstChild();
|
||||
nsIFrame* firstInlineFrame = nsnull;
|
||||
nsIFrame* lastInlineFrame = nsnull;
|
||||
while (kid) {
|
||||
if (IsInlineOutside(kid)) {
|
||||
if (!firstInlineFrame) firstInlineFrame = kid;
|
||||
lastInlineFrame = kid;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
kid = kid->GetNextSibling();
|
||||
// Find the part of aFrameItems that we want to put in the first-line
|
||||
nsFrameList::FrameLinkEnumerator link(aFrameItems);
|
||||
while (!link.AtEnd() && IsInlineOutside(link.NextFrame())) {
|
||||
link.Next();
|
||||
}
|
||||
|
||||
// If we don't find any inline frames, then there is nothing to do
|
||||
if (!firstInlineFrame) {
|
||||
return rv;
|
||||
nsFrameItems firstLineChildren = aFrameItems.ExtractHead(link);
|
||||
|
||||
if (firstLineChildren.IsEmpty()) {
|
||||
// Nothing is supposed to go into the first-line; nothing to do
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Create line frame
|
||||
nsStyleContext* parentStyle =
|
||||
nsFrame::CorrectStyleParentFrame(aBlockFrame,
|
||||
nsCSSPseudoElements::firstLine)->
|
||||
GetStyleContext();
|
||||
nsRefPtr<nsStyleContext> firstLineStyle = GetFirstLineStyle(aBlockContent,
|
||||
parentStyle);
|
||||
if (!aLineFrame) {
|
||||
// Create line frame
|
||||
nsStyleContext* parentStyle =
|
||||
nsFrame::CorrectStyleParentFrame(aBlockFrame,
|
||||
nsCSSPseudoElements::firstLine)->
|
||||
GetStyleContext();
|
||||
nsRefPtr<nsStyleContext> firstLineStyle = GetFirstLineStyle(aBlockContent,
|
||||
parentStyle);
|
||||
|
||||
nsIFrame* lineFrame = NS_NewFirstLineFrame(mPresShell, firstLineStyle);
|
||||
aLineFrame = NS_NewFirstLineFrame(mPresShell, firstLineStyle);
|
||||
|
||||
if (lineFrame) {
|
||||
// Initialize the line frame
|
||||
rv = InitAndRestoreFrame(aState, aBlockContent, aBlockFrame, nsnull,
|
||||
lineFrame);
|
||||
if (aLineFrame) {
|
||||
// Initialize the line frame
|
||||
rv = InitAndRestoreFrame(aState, aBlockContent, aBlockFrame, nsnull,
|
||||
aLineFrame);
|
||||
|
||||
// Mangle the list of frames we are giving to the block: first
|
||||
// chop the list in two after lastInlineFrame
|
||||
nsIFrame* secondBlockFrame = lastInlineFrame->GetNextSibling();
|
||||
lastInlineFrame->SetNextSibling(nsnull);
|
||||
// The lineFrame will be the block's first child; the rest of the
|
||||
// frame list (after lastInlineFrame) will be the second and
|
||||
// subsequent children; insert lineFrame into aFrameItems.
|
||||
aFrameItems.InsertFrame(nsnull, nsnull, aLineFrame);
|
||||
|
||||
// The lineFrame will be the block's first child; the rest of the
|
||||
// frame list (after lastInlineFrame) will be the second and
|
||||
// subsequent children; join the list together and reset
|
||||
// aFrameItems appropriately.
|
||||
if (secondBlockFrame) {
|
||||
lineFrame->SetNextSibling(secondBlockFrame);
|
||||
NS_ASSERTION(aLineFrame->GetStyleContext() == firstLineStyle,
|
||||
"Bogus style context on line frame");
|
||||
}
|
||||
if (aFrameItems.FirstChild() == lastInlineFrame) {
|
||||
// Just in case the block had exactly one inline child
|
||||
aFrameItems.lastChild = lineFrame;
|
||||
}
|
||||
aFrameItems.SetFrames(lineFrame);
|
||||
}
|
||||
|
||||
if (aLineFrame) {
|
||||
// Give the inline frames to the lineFrame <b>after</b> reparenting them
|
||||
kid = firstInlineFrame;
|
||||
NS_ASSERTION(lineFrame->GetStyleContext() == firstLineStyle,
|
||||
"Bogus style context on line frame");
|
||||
while (kid) {
|
||||
ReparentFrame(aState.mFrameManager, lineFrame, kid);
|
||||
kid = kid->GetNextSibling();
|
||||
ReparentFrames(aState.mFrameManager, aLineFrame, firstLineChildren);
|
||||
if (aLineFrame->GetChildList(nsnull).IsEmpty() &&
|
||||
(aLineFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
|
||||
aLineFrame->SetInitialChildList(nsnull, firstLineChildren);
|
||||
} else {
|
||||
aState.mFrameManager->AppendFrames(aLineFrame, nsnull,
|
||||
firstLineChildren.FirstChild());
|
||||
}
|
||||
lineFrame->SetInitialChildList(nsnull, firstInlineFrame);
|
||||
}
|
||||
else {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
@ -9723,66 +9712,25 @@ nsCSSFrameConstructor::AppendFirstLineFrames(
|
||||
{
|
||||
// It's possible that aBlockFrame needs to have a first-line frame
|
||||
// created because it doesn't currently have any children.
|
||||
nsIFrame* blockKid = aBlockFrame->GetFirstChild(nsnull);
|
||||
if (!blockKid) {
|
||||
const nsFrameList& blockKids = aBlockFrame->GetChildList(nsnull);
|
||||
if (blockKids.IsEmpty()) {
|
||||
return WrapFramesInFirstLineFrame(aState, aBlockContent,
|
||||
aBlockFrame, aFrameItems);
|
||||
aBlockFrame, nsnull, aFrameItems);
|
||||
}
|
||||
|
||||
// Examine the last block child - if it's a first-line frame then
|
||||
// appended frames need special treatment.
|
||||
nsresult rv = NS_OK;
|
||||
nsFrameList blockFrames(blockKid);
|
||||
nsIFrame* lastBlockKid = blockFrames.LastChild();
|
||||
nsIFrame* lastBlockKid = blockKids.LastChild();
|
||||
if (lastBlockKid->GetType() != nsGkAtoms::lineFrame) {
|
||||
// No first-line frame at the end of the list, therefore there is
|
||||
// an interveening block between any first-line frame the frames
|
||||
// an intervening block between any first-line frame the frames
|
||||
// we are appending. Therefore, we don't need any special
|
||||
// treatment of the appended frames.
|
||||
return rv;
|
||||
}
|
||||
nsIFrame* lineFrame = lastBlockKid;
|
||||
|
||||
// Find the first and last inline frame in aFrameItems
|
||||
nsIFrame* kid = aFrameItems.FirstChild();
|
||||
nsIFrame* firstInlineFrame = nsnull;
|
||||
nsIFrame* lastInlineFrame = nsnull;
|
||||
while (kid) {
|
||||
if (IsInlineOutside(kid)) {
|
||||
if (!firstInlineFrame) firstInlineFrame = kid;
|
||||
lastInlineFrame = kid;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
kid = kid->GetNextSibling();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// If we don't find any inline frames, then there is nothing to do
|
||||
if (!firstInlineFrame) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// The inline frames get appended to the lineFrame. Make sure they
|
||||
// are reparented properly.
|
||||
nsIFrame* remainingFrames = lastInlineFrame->GetNextSibling();
|
||||
lastInlineFrame->SetNextSibling(nsnull);
|
||||
kid = firstInlineFrame;
|
||||
while (kid) {
|
||||
ReparentFrame(aState.mFrameManager, lineFrame, kid);
|
||||
kid = kid->GetNextSibling();
|
||||
}
|
||||
aState.mFrameManager->AppendFrames(lineFrame, nsnull, firstInlineFrame);
|
||||
|
||||
// The remaining frames get appended to the block frame
|
||||
if (remainingFrames) {
|
||||
aFrameItems.SetFrames(remainingFrames);
|
||||
}
|
||||
else {
|
||||
aFrameItems.Clear();
|
||||
}
|
||||
|
||||
return rv;
|
||||
return WrapFramesInFirstLineFrame(aState, aBlockContent, aBlockFrame,
|
||||
lastBlockKid, aFrameItems);
|
||||
}
|
||||
|
||||
// Special routine to handle inserting a new frame into a block
|
||||
@ -10067,18 +10015,16 @@ nsCSSFrameConstructor::CreateFloatingLetterFrame(
|
||||
}
|
||||
|
||||
NS_ASSERTION(aResult.IsEmpty(), "aResult should be an empty nsFrameItems!");
|
||||
nsIFrame* insertAfter = nsnull;
|
||||
// Put the new float before any of the floats in the block we're
|
||||
// doing first-letter for, that is, before any floats whose parent is aBlockFrame
|
||||
for (nsFrameList::Enumerator e(aState.mFloatedItems); !e.AtEnd(); e.Next()) {
|
||||
if (e.get()->GetParent() == aBlockFrame)
|
||||
break;
|
||||
insertAfter = e.get();
|
||||
nsFrameList::FrameLinkEnumerator link(aState.mFloatedItems);
|
||||
while (!link.AtEnd() && link.NextFrame()->GetParent() != aBlockFrame) {
|
||||
link.Next();
|
||||
}
|
||||
|
||||
rv = aState.AddChild(letterFrame, aResult, letterContent, aStyleContext,
|
||||
aParentFrame, PR_FALSE, PR_TRUE, PR_FALSE, PR_TRUE,
|
||||
insertAfter);
|
||||
link.PrevFrame());
|
||||
|
||||
if (nextTextFrame) {
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -87,6 +87,13 @@ struct nsFrameItems : public nsFrameList {
|
||||
|
||||
nsFrameItems(nsIFrame* aFrame = nsnull);
|
||||
|
||||
nsFrameItems(const nsFrameList& aList, nsIFrame* aLastChild) :
|
||||
nsFrameList(aList),
|
||||
lastChild(aLastChild)
|
||||
{
|
||||
NS_ASSERTION(LastChild() == lastChild, "Bogus aLastChild");
|
||||
}
|
||||
|
||||
// Appends the frame to the end of the list
|
||||
void AddChild(nsIFrame* aChild);
|
||||
|
||||
@ -133,12 +140,32 @@ struct nsFrameItems : public nsFrameList {
|
||||
return removed;
|
||||
}
|
||||
|
||||
nsFrameItems ExtractHead(FrameLinkEnumerator& aLink) {
|
||||
nsIFrame* newLastChild = aLink.PrevFrame();
|
||||
if (lastChild && aLink.NextFrame() == lastChild) {
|
||||
lastChild = nsnull;
|
||||
}
|
||||
return nsFrameItems(nsFrameList::ExtractHead(aLink),
|
||||
newLastChild);
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
mFirstChild = lastChild = nsnull;
|
||||
}
|
||||
|
||||
// For now, until we change some SetInitialChildList signatures
|
||||
operator nsIFrame* () { return FirstChild(); }
|
||||
|
||||
private:
|
||||
// Not implemented; shouldn't be called
|
||||
void SetFrames(nsIFrame* aFrameList);
|
||||
void AppendFrames(nsIFrame* aParent, nsIFrame* aFrameList);
|
||||
Slice AppendFrames(nsIFrame* aParent, nsFrameList& aFrameList);
|
||||
void AppendFrame(nsIFrame* aParent, nsIFrame* aFrame);
|
||||
PRBool RemoveFirstChild();
|
||||
void InsertFrames(nsIFrame* aParent, nsIFrame* aPrevSibling,
|
||||
nsIFrame* aFrameList);
|
||||
void SortByContentOrder();
|
||||
};
|
||||
|
||||
class nsCSSFrameConstructor
|
||||
@ -1590,11 +1617,21 @@ private:
|
||||
|
||||
// Methods support :first-line style
|
||||
|
||||
// This method chops the initial inline-outside frames out of aFrameItems.
|
||||
// If aLineFrame is non-null, it appends them to that frame. Otherwise, it
|
||||
// creates a new line frame, sets the inline frames as its initial child
|
||||
// list, and inserts that line frame at the front of what's left of
|
||||
// aFrameItems. In both cases, the kids are reparented to the line frame.
|
||||
// After this call, aFrameItems holds the frames that need to become kids of
|
||||
// the block (possibly including line frames).
|
||||
nsresult WrapFramesInFirstLineFrame(nsFrameConstructorState& aState,
|
||||
nsIContent* aBlockContent,
|
||||
nsIFrame* aBlockFrame,
|
||||
nsIFrame* aLineFrame,
|
||||
nsFrameItems& aFrameItems);
|
||||
|
||||
// Handle the case when a block with first-line style is appended to (by
|
||||
// possibly calling WrapFramesInFirstLineFrame as needed).
|
||||
nsresult AppendFirstLineFrames(nsFrameConstructorState& aState,
|
||||
nsIContent* aContent,
|
||||
nsIFrame* aBlockFrame,
|
||||
|
@ -266,20 +266,29 @@ nsFrameList::InsertFrames(nsIFrame* aParent,
|
||||
#endif
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsFrameList::Split(nsIFrame* aAfterFrame, nsIFrame** aNextFrameResult)
|
||||
nsFrameList
|
||||
nsFrameList::ExtractHead(FrameLinkEnumerator& aLink)
|
||||
{
|
||||
NS_PRECONDITION(nsnull != aAfterFrame, "null ptr");
|
||||
NS_PRECONDITION(nsnull != aNextFrameResult, "null ptr");
|
||||
NS_ASSERTION(ContainsFrame(aAfterFrame), "split after unknown frame");
|
||||
NS_PRECONDITION(&aLink.List() == this, "Unexpected list");
|
||||
NS_PRECONDITION(!aLink.PrevFrame() ||
|
||||
aLink.PrevFrame()->GetNextSibling() ==
|
||||
aLink.NextFrame(),
|
||||
"Unexpected PrevFrame()");
|
||||
|
||||
if (aNextFrameResult && aAfterFrame) {
|
||||
nsIFrame* nextFrame = aAfterFrame->GetNextSibling();
|
||||
aAfterFrame->SetNextSibling(nsnull);
|
||||
*aNextFrameResult = nextFrame;
|
||||
return PR_TRUE;
|
||||
nsIFrame* prev = aLink.PrevFrame();
|
||||
nsIFrame* newFirstFrame = nsnull;
|
||||
if (prev) {
|
||||
// Truncate the list after |prev| and hand the first part to our new list.
|
||||
prev->SetNextSibling(nsnull);
|
||||
newFirstFrame = mFirstChild;
|
||||
mFirstChild = aLink.NextFrame();
|
||||
|
||||
// Now make sure aLink doesn't point to a frame we no longer have.
|
||||
aLink.mPrev = nsnull;
|
||||
}
|
||||
return PR_FALSE;
|
||||
// else aLink is pointing to before our first frame. Nothing to do.
|
||||
|
||||
return nsFrameList(newFirstFrame);
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
|
@ -172,7 +172,13 @@ public:
|
||||
inline Slice InsertFrames(nsIFrame* aParent, nsIFrame* aPrevSibling,
|
||||
nsFrameList& aFrameList);
|
||||
|
||||
PRBool Split(nsIFrame* aAfterFrame, nsIFrame** aNextFrameResult);
|
||||
class FrameLinkEnumerator;
|
||||
|
||||
/* Split this frame list such that all the frames before the link pointed to
|
||||
* by aLink end up in the returned list, while the remaining frames stay in
|
||||
* this list. After this call, aLink points to the beginning of this list.
|
||||
*/
|
||||
nsFrameList ExtractHead(FrameLinkEnumerator& aLink);
|
||||
|
||||
/**
|
||||
* Sort the frames according to content order so that the first
|
||||
@ -310,7 +316,11 @@ public:
|
||||
|
||||
nsIFrame* get() const { return mFrame; }
|
||||
|
||||
private:
|
||||
#ifdef DEBUG
|
||||
const nsFrameList& List() const { return mSlice.mList; }
|
||||
#endif
|
||||
|
||||
protected:
|
||||
#ifdef DEBUG
|
||||
const Slice& mSlice;
|
||||
#endif
|
||||
@ -319,6 +329,43 @@ public:
|
||||
// May be null.
|
||||
};
|
||||
|
||||
/**
|
||||
* A class that can be used to enumerate links between frames. When created
|
||||
* from an nsFrameList, it points to the "link" immediately before the first
|
||||
* frame. It can then be advanced until it points to the "link" immediately
|
||||
* after the last frame. At any position, PrevFrame() and NextFrame() are
|
||||
* the frames before and after the given link. This means PrevFrame() is
|
||||
* null when the enumerator is at the beginning of the list and NextFrame()
|
||||
* is null when it's AtEnd().
|
||||
*/
|
||||
class FrameLinkEnumerator : private Enumerator {
|
||||
public:
|
||||
friend class nsFrameList;
|
||||
|
||||
FrameLinkEnumerator(const nsFrameList& aList) :
|
||||
Enumerator(aList),
|
||||
mPrev(nsnull)
|
||||
{}
|
||||
|
||||
FrameLinkEnumerator(const FrameLinkEnumerator& aOther) :
|
||||
Enumerator(aOther),
|
||||
mPrev(aOther.mPrev)
|
||||
{}
|
||||
|
||||
void Next() {
|
||||
mPrev = mFrame;
|
||||
Enumerator::Next();
|
||||
}
|
||||
|
||||
PRBool AtEnd() const { return Enumerator::AtEnd(); }
|
||||
|
||||
nsIFrame* PrevFrame() const { return mPrev; }
|
||||
nsIFrame* NextFrame() const { return mFrame; }
|
||||
|
||||
protected:
|
||||
nsIFrame* mPrev;
|
||||
};
|
||||
|
||||
private:
|
||||
#ifdef DEBUG
|
||||
void CheckForLoops();
|
||||
|
Loading…
Reference in New Issue
Block a user