diff --git a/mozilla/layout/base/nsFrameManager.cpp b/mozilla/layout/base/nsFrameManager.cpp index b020a6a7849..11e4f45afd1 100644 --- a/mozilla/layout/base/nsFrameManager.cpp +++ b/mozilla/layout/base/nsFrameManager.cpp @@ -371,10 +371,10 @@ public: nsIAtom* aPropertyName, PRUint32 aOptions, void** aPropertyValue); - NS_IMETHOD SetFrameProperty(nsIFrame* aFrame, - nsIAtom* aPropertyName, - void* aPropertyValue, - NSFMPropertyDtorFunc aPropDtorFunc); + NS_IMETHOD SetFrameProperty(nsIFrame* aFrame, + nsIAtom* aPropertyName, + void* aPropertyValue, + NSFramePropertyDtorFunc aPropDtorFunc); NS_IMETHOD RemoveFrameProperty(nsIFrame* aFrame, nsIAtom* aPropertyName); @@ -383,13 +383,13 @@ public: #endif struct PropertyList { - nsCOMPtr mName; // property name - PLDHashTable mFrameValueMap; // map of frame/value pairs - NSFMPropertyDtorFunc mDtorFunc; // property specific value dtor function - PropertyList* mNext; + nsCOMPtr mName; // property name + PLDHashTable mFrameValueMap; // map of frame/value pairs + NSFramePropertyDtorFunc mDtorFunc; // property specific value dtor function + PropertyList* mNext; - PropertyList(nsIAtom* aName, - NSFMPropertyDtorFunc aDtorFunc); + PropertyList(nsIAtom* aName, + NSFramePropertyDtorFunc aDtorFunc); ~PropertyList(); // Removes the property associated with the given frame, and destroys @@ -2452,10 +2452,10 @@ FrameManager::GetFrameProperty(nsIFrame* aFrame, } NS_IMETHODIMP -FrameManager::SetFrameProperty(nsIFrame* aFrame, - nsIAtom* aPropertyName, - void* aPropertyValue, - NSFMPropertyDtorFunc aPropDtorFunc) +FrameManager::SetFrameProperty(nsIFrame* aFrame, + nsIAtom* aPropertyName, + void* aPropertyValue, + NSFramePropertyDtorFunc aPropDtorFunc) { NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_AVAILABLE); NS_PRECONDITION(aPropertyName && aFrame, "unexpected null param"); @@ -2667,8 +2667,8 @@ UndisplayedMap::Clear(void) //---------------------------------------------------------------------- -FrameManager::PropertyList::PropertyList(nsIAtom* aName, - NSFMPropertyDtorFunc aDtorFunc) +FrameManager::PropertyList::PropertyList(nsIAtom* aName, + NSFramePropertyDtorFunc aDtorFunc) : mName(aName), mDtorFunc(aDtorFunc), mNext(nsnull) { PL_DHashTableInit(&mFrameValueMap, PL_DHashGetStubOps(), this, diff --git a/mozilla/layout/base/public/nsIFrame.h b/mozilla/layout/base/public/nsIFrame.h index 1d2951186eb..b9de9beb248 100644 --- a/mozilla/layout/base/public/nsIFrame.h +++ b/mozilla/layout/base/public/nsIFrame.h @@ -90,6 +90,13 @@ struct nsRect; struct nsSize; struct nsMargin; +// Calback function used to destroy the value associated with a property. +typedef void +(*NSFramePropertyDtorFunc)(nsIPresContext* aPresContext, + nsIFrame* aFrame, + nsIAtom* aPropertyName, + void* aPropertyValue); + // IID for the nsIFrame interface // a6cf9050-15b3-11d2-932e-00805f8add32 #define NS_IFRAME_IID \ @@ -1158,6 +1165,14 @@ public: PRBool aIsPre, PRBool* aResult) = 0; + virtual void* GetProperty(nsIPresContext* aPresContext, + nsIAtom* aPropertyName, + PRBool aRemoveProperty) const = 0; + + virtual nsresult SetProperty(nsIPresContext* aPresContext, + nsIAtom* aPropertyName, + void* aPropertyValue, + NSFramePropertyDtorFunc aPropDtorFunc) = 0; #ifdef IBMBIDI /** * retrieve and set Bidi property of this frame diff --git a/mozilla/layout/base/public/nsIFrameManager.h b/mozilla/layout/base/public/nsIFrameManager.h index d67910dfddd..a1182e031d0 100644 --- a/mozilla/layout/base/public/nsIFrameManager.h +++ b/mozilla/layout/base/public/nsIFrameManager.h @@ -41,10 +41,10 @@ #include "nsIStatefulFrame.h" #include "nsString.h" #include "nsChangeHint.h" +#include "nsIFrame.h" class nsIAtom; class nsIContent; -class nsIFrame; class nsIPresContext; class nsIPresShell; class nsIStyleSet; @@ -57,14 +57,6 @@ class nsPlaceholderFrame; { 0xa6cf9107, 0x15b3, 0x11d2, \ {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } -// Calback function used to destroy the value associated with a -// given property. used by RemoveFrameProperty() -typedef void -(*NSFMPropertyDtorFunc)(nsIPresContext* aPresContext, - nsIFrame* aFrame, - nsIAtom* aPropertyName, - void* aPropertyValue); - // Option flags for GetFrameProperty() member function #define NS_IFRAME_MGR_REMOVE_PROP 0x0001 @@ -233,10 +225,10 @@ public: * NS_ERROR_INVALID_ARG if the dtor function does not match the * existing dtor function */ - NS_IMETHOD SetFrameProperty(nsIFrame* aFrame, - nsIAtom* aPropertyName, - void* aPropertyValue, - NSFMPropertyDtorFunc aPropertyDtorFunc) = 0; + NS_IMETHOD SetFrameProperty(nsIFrame* aFrame, + nsIAtom* aPropertyName, + void* aPropertyValue, + NSFramePropertyDtorFunc aPropertyDtorFunc) = 0; /** * Removes a property and destroys its property value by calling the dtor diff --git a/mozilla/layout/generic/nsBlockFrame.cpp b/mozilla/layout/generic/nsBlockFrame.cpp index bd23d692fac..1611bfd6370 100644 --- a/mozilla/layout/generic/nsBlockFrame.cpp +++ b/mozilla/layout/generic/nsBlockFrame.cpp @@ -945,42 +945,78 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, NS_ASSERTION(NS_SUCCEEDED(rv), "reflow dirty lines failed"); if (NS_FAILED(rv)) return rv; - // Put continued floaters at the beginning of the first overflow line. If the first line - // is a block then create a new line as the first line and put the floaters there. If there - // are no overflow lines, then create one and put the floaters in it. - if (state.mOverflowFloaters.NotEmpty()) { - nsLineList* overflowLines = GetOverflowLines(aPresContext, PR_FALSE); - if (overflowLines) { - line_iterator firstLine = overflowLines->begin(); - if (firstLine->IsBlock()) { // floaters go on a new line before 1st overflow line - nsLineBox* newLine = state.NewLineBox(state.mOverflowFloaters.FirstChild(), - state.mOverflowFloaters.GetLength(), PR_FALSE); - firstLine = mLines.before_insert(firstLine, newLine); - } - else { // floaters go on 1st overflow line - nsIFrame* firstFrame = firstLine->mFirstChild; - firstLine->mFirstChild = state.mOverflowFloaters.FirstChild(); - PRInt32 numOverflowFloaters = state.mOverflowFloaters.GetLength(); - // hook up the last placeholder with the original frames - nsPlaceholderFrame* lastPlaceholder = - (nsPlaceholderFrame*)state.mOverflowFloaters.LastChild(); - lastPlaceholder->SetNextSibling(firstFrame); - NS_ASSERTION(firstFrame != lastPlaceholder, "trying to set next sibling to self"); - firstLine->SetChildCount(firstLine->GetChildCount() + numOverflowFloaters); + // If the block is complete, put continuted floaters in the closest ancestor + // block that uses the same space manager and leave the block complete; this + // allows subsequent lines on the page to be impacted by floaters. If the + // block is incomplete or there is no ancestor using the same space manager, + // put continued floaters at the beginning of the first overflow line. + nsFrameList* overflowPlace = nsnull; + if ((NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight) && + (overflowPlace = GetOverflowPlaceholders(aPresContext, PR_TRUE))) { + PRBool gaveToAncestor = PR_FALSE; + if (NS_FRAME_IS_COMPLETE(state.mReflowStatus)) { + // find the nearest block ancestor that uses the same space manager + for (const nsHTMLReflowState* ancestorRS = aReflowState.parentReflowState; + ancestorRS; + ancestorRS = ancestorRS->parentReflowState) { + nsIFrame* ancestor = ancestorRS->frame; + nsCOMPtr fType; + ancestor->GetFrameType(getter_AddRefs(fType)); + if ((nsLayoutAtoms::blockFrame == fType) || (nsLayoutAtoms::areaFrame == fType)) { + if (aReflowState.mSpaceManager == ancestorRS->mSpaceManager) { + // Put the continued floaters in ancestor since it uses the same space manager + nsFrameList* ancestorPlace = + ((nsBlockFrame*)ancestor)->GetOverflowPlaceholders(aPresContext, PR_FALSE); + if (ancestorPlace) { + ancestorPlace->AppendFrames(ancestor, overflowPlace->FirstChild()); + } + else { + ancestorPlace = new nsFrameList(overflowPlace->FirstChild()); + if (ancestorPlace) { + ((nsBlockFrame*)ancestor)->SetOverflowPlaceholders(aPresContext, ancestorPlace); + } + else + return NS_ERROR_OUT_OF_MEMORY; + } + gaveToAncestor = PR_TRUE; + break; + } + } } } - else { - // Create a line, put the floaters in it, and then push. - nsLineBox* newLine = state.NewLineBox(state.mOverflowFloaters.FirstChild(), - state.mOverflowFloaters.GetLength(), PR_FALSE); - if (!newLine) - return NS_ERROR_OUT_OF_MEMORY; - mLines.push_back(newLine); - nsLineList::iterator nextToLastLine = ----end_lines(); - PushLines(state, nextToLastLine); + if (!gaveToAncestor) { + PRInt32 numOverflowPlace = overflowPlace->GetLength(); + nsLineList* overflowLines = GetOverflowLines(aPresContext, PR_FALSE); + if (overflowLines) { + line_iterator firstLine = overflowLines->begin(); + if (firstLine->IsBlock()) { + // Create a new line as the first line and put the floaters there; + nsLineBox* newLine = state.NewLineBox(overflowPlace->FirstChild(), numOverflowPlace, PR_FALSE); + firstLine = mLines.before_insert(firstLine, newLine); + } + else { // floaters go on 1st overflow line + nsIFrame* firstFrame = firstLine->mFirstChild; + firstLine->mFirstChild = overflowPlace->FirstChild(); + // hook up the last placeholder with the original frames + nsPlaceholderFrame* lastPlaceholder = + (nsPlaceholderFrame*)overflowPlace->LastChild(); + lastPlaceholder->SetNextSibling(firstFrame); + NS_ASSERTION(firstFrame != lastPlaceholder, "trying to set next sibling to self"); + firstLine->SetChildCount(firstLine->GetChildCount() + numOverflowPlace); + } + } + else { + // Create a line, put the floaters in it, and then push. + nsLineBox* newLine = state.NewLineBox(overflowPlace->FirstChild(), numOverflowPlace, PR_FALSE); + if (!newLine) + return NS_ERROR_OUT_OF_MEMORY; + mLines.push_back(newLine); + nsLineList::iterator nextToLastLine = ----end_lines(); + PushLines(state, nextToLastLine); + } + state.mReflowStatus = NS_FRAME_NOT_COMPLETE; } - state.mReflowStatus = NS_FRAME_NOT_COMPLETE; - state.mOverflowFloaters.SetFrames(nsnull); + delete overflowPlace; } if (NS_FRAME_IS_NOT_COMPLETE(state.mReflowStatus)) { @@ -3151,9 +3187,9 @@ nsBlockFrame::GetTopBlockChild(nsIPresContext* aPresContext) // If placeholders/floaters split during reflowing a line, but that line will // be put on the next page, then put the placeholders/floaters back the way // they were before the line was reflowed. -static void -UndoPlaceholders(nsBlockReflowState& aState, - nsIFrame* aLastPlaceholder) +void +nsBlockFrame::UndoSplitPlaceholders(nsBlockReflowState& aState, + nsIFrame* aLastPlaceholder) { nsIFrame* undoPlaceholder = nsnull; if (aLastPlaceholder) { @@ -3161,8 +3197,9 @@ UndoPlaceholders(nsBlockReflowState& aState, aLastPlaceholder->SetNextSibling(nsnull); } else { - undoPlaceholder = aState.mOverflowFloaters.FirstChild(); - aState.mOverflowFloaters.SetFrames(nsnull); + // just remove the property + nsFrameList* overflowPlace = GetOverflowPlaceholders(aState.mPresContext, PR_TRUE); + delete overflowPlace; } // remove the next in flows of the placeholders that need to be removed for (nsIFrame* placeholder = undoPlaceholder; placeholder; ) { @@ -3320,7 +3357,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, } // keep track of the last overflow floater in case we need to undo any new additions - nsIFrame* lastPlaceholder = aState.mOverflowFloaters.LastChild(); + nsFrameList* overflowPlace = GetOverflowPlaceholders(aState.mPresContext, PR_FALSE); + nsIFrame* lastPlaceholder = (overflowPlace) ? overflowPlace->LastChild() : nsnull; // Reflow the block into the available space nsReflowStatus frameReflowStatus=NS_FRAME_COMPLETE; @@ -3353,7 +3391,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, if (NS_INLINE_IS_BREAK_BEFORE(frameReflowStatus)) { // None of the child block fits. - ::UndoPlaceholders(aState, lastPlaceholder); + UndoSplitPlaceholders(aState, lastPlaceholder); PushLines(aState, aLine.prev()); *aKeepReflowGoing = PR_FALSE; aState.mReflowStatus = NS_FRAME_NOT_COMPLETE; @@ -3530,7 +3568,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, else { // Push the line that didn't fit and any lines that follow it // to our next-in-flow. - ::UndoPlaceholders(aState, lastPlaceholder); + UndoSplitPlaceholders(aState, lastPlaceholder); PushLines(aState, aLine.prev()); aState.mReflowStatus = NS_FRAME_NOT_COMPLETE; } @@ -3644,7 +3682,7 @@ nsBlockFrame::PushTruncatedPlaceholderLine(nsBlockReflowState& aState, nsIFrame* aLastPlaceholder, PRBool& aKeepReflowGoing) { - ::UndoPlaceholders(aState, aLastPlaceholder); + UndoSplitPlaceholders(aState, aLastPlaceholder); line_iterator prevLine = aLine; --prevLine; @@ -3716,7 +3754,8 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState, } // keep track of the last overflow floater in case we need to undo any new additions - nsIFrame* lastPlaceholder = aState.mOverflowFloaters.LastChild(); + nsFrameList* overflowPlace = GetOverflowPlaceholders(aState.mPresContext, PR_FALSE); + nsIFrame* lastPlaceholder = (overflowPlace) ? overflowPlace->LastChild() : nsnull; // Reflow the frames that are already on the line first nsresult rv = NS_OK; @@ -3814,7 +3853,7 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState, // no point in placing the line. if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) { if (PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing, aUpdateMaximumWidth)) { - ::UndoPlaceholders(aState, lastPlaceholder); // undo since we pushed the current line + UndoSplitPlaceholders(aState, lastPlaceholder); // undo since we pushed the current line } } } @@ -3991,7 +4030,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState, // frame may already have a continuation. PRBool madeContinuation; rv = (nsLayoutAtoms::placeholderFrame == frameType) - ? SplitPlaceholder(aState, *aFrame) + ? SplitPlaceholder(*aState.mPresContext, *aFrame) : CreateContinuationFor(aState, aLine, aFrame, madeContinuation); if (NS_FAILED(rv)) return rv; @@ -4070,11 +4109,11 @@ nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState, } nsresult -nsBlockFrame::SplitPlaceholder(nsBlockReflowState& aState, - nsIFrame& aPlaceholder) +nsBlockFrame::SplitPlaceholder(nsIPresContext& aPresContext, + nsIFrame& aPlaceholder) { nsIFrame* nextInFlow; - nsresult rv = CreateNextInFlow(aState.mPresContext, this, &aPlaceholder, nextInFlow); + nsresult rv = CreateNextInFlow(&aPresContext, this, &aPlaceholder, nextInFlow); if (NS_FAILED(rv)) return rv; // put the sibling list back to what it was before the continuation was created @@ -4084,7 +4123,17 @@ nsBlockFrame::SplitPlaceholder(nsBlockReflowState& aState, aPlaceholder.SetNextSibling(next); contFrame->SetNextSibling(nsnull); // add the placehoder to the overflow floaters - aState.mOverflowFloaters.AppendFrames(this, contFrame); + nsFrameList* overflowPlace = GetOverflowPlaceholders(&aPresContext, PR_FALSE); + if (overflowPlace) { + overflowPlace->AppendFrames(this, contFrame); + } + else { + overflowPlace = new nsFrameList(contFrame); + if (overflowPlace) { + SetOverflowPlaceholders(&aPresContext, overflowPlace); + } + else return NS_ERROR_NULL_POINTER; + } return NS_OK; } @@ -4415,7 +4464,8 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, // Any below current line floaters to place? if (aState.mBelowCurrentLineFloaters.NotEmpty()) { // keep track of the last overflow floater in case we need to undo and push the line - nsIFrame* lastPlaceholder = aState.mOverflowFloaters.LastChild(); + nsFrameList* overflowPlace = GetOverflowPlaceholders(aState.mPresContext, PR_FALSE); + nsIFrame* lastPlaceholder = (overflowPlace) ? overflowPlace->LastChild() : nsnull; // Reflow the below-current-line floaters, then add them to the // lines floater list if there aren't any truncated floaters. if (aState.PlaceBelowCurrentLineFloaters(aState.mBelowCurrentLineFloaters)) { @@ -4739,31 +4789,12 @@ nsLineList* nsBlockFrame::GetOverflowLines(nsIPresContext* aPresContext, PRBool aRemoveProperty) const { - nsCOMPtr presShell; - aPresContext->GetShell(getter_AddRefs(presShell)); - - if (presShell) { - nsCOMPtr frameManager; - presShell->GetFrameManager(getter_AddRefs(frameManager)); - - if (frameManager) { - PRUint32 options = 0; - nsLineList* value; - - if (aRemoveProperty) { - options |= NS_IFRAME_MGR_REMOVE_PROP; - } - frameManager->GetFrameProperty(NS_CONST_CAST(nsBlockFrame*, this), - nsLayoutAtoms::overflowLinesProperty, - options, - NS_REINTERPRET_CAST(void**, &value)); - NS_ASSERTION(!value || !value->empty(), - "value should never be stored as empty"); - return value; - } - } - - return nsnull; + nsLineList* lines = + NS_STATIC_CAST(nsLineList*, GetProperty(aPresContext, + nsLayoutAtoms::overflowLinesProperty, + aRemoveProperty)); + NS_ASSERTION(!lines || !lines->empty(), "value should never be stored as empty"); + return lines; } // Destructor function for the overflowLines frame property @@ -4786,27 +4817,48 @@ nsresult nsBlockFrame::SetOverflowLines(nsIPresContext* aPresContext, nsLineList* aOverflowLines) { - nsCOMPtr presShell; - nsresult rv = NS_ERROR_FAILURE; - NS_ASSERTION(aOverflowLines, "null lines"); - NS_ASSERTION(! aOverflowLines->empty(), "empty lines"); + NS_ASSERTION(!aOverflowLines->empty(), "empty lines"); - aPresContext->GetShell(getter_AddRefs(presShell)); - if (presShell) { - nsCOMPtr frameManager; - presShell->GetFrameManager(getter_AddRefs(frameManager)); - - if (frameManager) { - rv = frameManager->SetFrameProperty(this, - nsLayoutAtoms::overflowLinesProperty, - aOverflowLines, - DestroyOverflowLines); + nsresult rv = SetProperty(aPresContext, nsLayoutAtoms::overflowLinesProperty, + aOverflowLines, DestroyOverflowLines); + // Verify that we didn't overwrite an existing overflow list + NS_ASSERTION(rv != NS_IFRAME_MGR_PROP_OVERWRITTEN, "existing overflow list"); + return rv; +} - // Verify that we didn't overwrite an existing overflow list - NS_ASSERTION(rv != NS_IFRAME_MGR_PROP_OVERWRITTEN, "existing overflow list"); - } - } +nsFrameList* +nsBlockFrame::GetOverflowPlaceholders(nsIPresContext* aPresContext, + PRBool aRemoveProperty) const +{ + nsFrameList* placeholders = + NS_STATIC_CAST(nsFrameList*, + GetProperty(aPresContext, nsLayoutAtoms::overflowPlaceholdersProperty, + aRemoveProperty)); + return placeholders; +} + +// Destructor function for the overflowPlaceholders frame property +static void +DestroyOverflowPlaceholders(nsIPresContext* aPresContext, + nsIFrame* aFrame, + nsIAtom* aPropertyName, + void* aPropertyValue) +{ + nsFrameList* overflowPlace = NS_STATIC_CAST(nsFrameList*, aPropertyValue); + delete overflowPlace; +} + +// This takes ownership of aOverflowLines. +// XXX We should allocate overflowLines from presShell arena! +nsresult +nsBlockFrame::SetOverflowPlaceholders(nsIPresContext* aPresContext, + nsFrameList* aOverflowPlaceholders) +{ + nsresult rv = SetProperty(aPresContext, nsLayoutAtoms::overflowPlaceholdersProperty, + aOverflowPlaceholders, DestroyOverflowPlaceholders); + // Verify that we didn't overwrite an existing overflow list + NS_ASSERTION(rv != NS_IFRAME_MGR_PROP_OVERWRITTEN, "existing overflow placeholder list"); return rv; } diff --git a/mozilla/layout/generic/nsBlockFrame.h b/mozilla/layout/generic/nsBlockFrame.h index e6c419febdd..81f9d5ae5bb 100644 --- a/mozilla/layout/generic/nsBlockFrame.h +++ b/mozilla/layout/generic/nsBlockFrame.h @@ -201,9 +201,11 @@ public: // Create a contination for aPlaceholder and its out of flow frame and // add it to the list of overflow floaters - nsresult SplitPlaceholder(nsBlockReflowState& aState, - nsIFrame& aPlaceholder); + nsresult SplitPlaceholder(nsIPresContext& aPresContext, nsIFrame& aPlaceholder); + void UndoSplitPlaceholders(nsBlockReflowState& aState, + nsIFrame* aLastPlaceholder); + protected: nsBlockFrame(); virtual ~nsBlockFrame(); @@ -503,6 +505,12 @@ protected: nsresult SetOverflowLines(nsIPresContext* aPresContext, nsLineList* aOverflowLines); + nsFrameList* GetOverflowPlaceholders(nsIPresContext* aPresContext, + PRBool aRemoveProperty) const; + + nsresult SetOverflowPlaceholders(nsIPresContext* aPresContext, + nsFrameList* aOverflowPlaceholders); + nsIFrame* LastChild(); #ifdef NS_DEBUG diff --git a/mozilla/layout/generic/nsBlockReflowState.cpp b/mozilla/layout/generic/nsBlockReflowState.cpp index 84dcf843c4b..1f5558cf6df 100644 --- a/mozilla/layout/generic/nsBlockReflowState.cpp +++ b/mozilla/layout/generic/nsBlockReflowState.cpp @@ -46,6 +46,7 @@ #include "nsIPresContext.h" #include "nsLayoutAtoms.h" #include "nsIFrame.h" +#include "nsIFrameManager.h" #include "nsINameSpaceManager.h" #include "nsHTMLAtoms.h" @@ -124,7 +125,6 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, } } mHaveRightFloaters = PR_FALSE; - mOverflowFloaters.SetFrames(nsnull); // Compute content area height. Unlike the width, if we have a // specified style height we ignore it since extra content is @@ -847,7 +847,8 @@ nsBlockReflowState::FlowAndPlaceFloater(nsFloaterCache* aFloaterCache, // content. nscoord saveY = mY; - nsIFrame* floater = aFloaterCache->mPlaceholder->GetOutOfFlowFrame(); + nsPlaceholderFrame* placeholder = aFloaterCache->mPlaceholder; + nsIFrame* floater = placeholder->GetOutOfFlowFrame(); // Grab the floater's display information const nsStyleDisplay* floaterDisplay; @@ -879,8 +880,8 @@ nsBlockReflowState::FlowAndPlaceFloater(nsFloaterCache* aFloaterCache, } // Reflow the floater - mBlock->ReflowFloater(*this, aFloaterCache->mPlaceholder, aFloaterCache->mCombinedArea, - aFloaterCache->mMargins, aFloaterCache->mOffsets, aReflowStatus); + mBlock->ReflowFloater(*this, placeholder, aFloaterCache->mCombinedArea, + aFloaterCache->mMargins, aFloaterCache->mOffsets, aReflowStatus); // Get the floaters bounding box and margin information floater->GetRect(region); @@ -963,7 +964,7 @@ nsBlockReflowState::FlowAndPlaceFloater(nsFloaterCache* aFloaterCache, mY += mAvailSpaceRect.height; GetAvailableSpace(); // reflow the floater again now since we have more space - mBlock->ReflowFloater(*this, aFloaterCache->mPlaceholder, aFloaterCache->mCombinedArea, + mBlock->ReflowFloater(*this, placeholder, aFloaterCache->mCombinedArea, aFloaterCache->mMargins, aFloaterCache->mOffsets, aReflowStatus); // Get the floaters bounding box and margin information floater->GetRect(region); @@ -974,12 +975,33 @@ nsBlockReflowState::FlowAndPlaceFloater(nsFloaterCache* aFloaterCache, } } - // If the floater is continued, it will get the same x value as its prev-in-flow - nsRect prevInFlowRect(0,0,0,0); + // If the floater is continued, it will get the same absolute x value as its prev-in-flow + nsRect prevRect(0,0,0,0); nsIFrame* prevInFlow; floater->GetPrevInFlow(&prevInFlow); if (prevInFlow) { - prevInFlow->GetRect(prevInFlowRect); + prevInFlow->GetRect(prevRect); + + nsCOMPtr presShell; + mPresContext->GetShell(getter_AddRefs(presShell)); + nsCOMPtr frameManager; + presShell->GetFrameManager(getter_AddRefs(frameManager)); + + nsIFrame *placeParent, *placeParentPrev, *prevPlace, *prevPlaceParent; + // If prevInFlow's placeholder is in a block that wasn't continued, we need to adjust + // prevRect.x to account for the missing frame offsets. + placeholder->GetParent(&placeParent); + placeParent->GetPrevInFlow(&placeParentPrev); + frameManager->GetPlaceholderFrameFor(prevInFlow, &prevPlace); + prevPlace->GetParent(&prevPlaceParent); + + for (nsIFrame* ancestor = prevPlaceParent; + ancestor && (ancestor != placeParentPrev); + ancestor->GetParent(&ancestor)) { + nsRect rect; + ancestor->GetRect(rect); + prevRect.x += rect.x; + } } // Assign an x and y coordinate to the floater. Note that the x,y // coordinates are computed relative to the translation in the @@ -989,7 +1011,7 @@ nsBlockReflowState::FlowAndPlaceFloater(nsFloaterCache* aFloaterCache, PRBool isLeftFloater; if (NS_STYLE_FLOAT_LEFT == floaterDisplay->mFloats) { isLeftFloater = PR_TRUE; - region.x = (prevInFlow) ? prevInFlowRect.x : mAvailSpaceRect.x; + region.x = (prevInFlow) ? prevRect.x : mAvailSpaceRect.x; } else { isLeftFloater = PR_FALSE; @@ -997,7 +1019,7 @@ nsBlockReflowState::FlowAndPlaceFloater(nsFloaterCache* aFloaterCache, nsIFrame* prevInFlow; floater->GetPrevInFlow(&prevInFlow); if (prevInFlow) { - region.x = prevInFlowRect.x; + region.x = prevRect.x; } else if (!keepFloaterOnSameLine) { region.x = mAvailSpaceRect.XMost() - region.width; @@ -1030,7 +1052,7 @@ nsBlockReflowState::FlowAndPlaceFloater(nsFloaterCache* aFloaterCache, // if the floater split, then take up all of the vertical height if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus) && (NS_UNCONSTRAINEDSIZE != mContentArea.height)) { - region.height += PR_MAX(region.height, mContentArea.height); + region.height = PR_MAX(region.height, mContentArea.height); } #ifdef DEBUG nsresult rv = @@ -1160,7 +1182,7 @@ nsBlockReflowState::PlaceBelowCurrentLineFloaters(nsFloaterCacheList& aList) } else if (NS_FRAME_IS_NOT_COMPLETE(reflowStatus)) { // Create a continuation for the incomplete floater and its placeholder. - nsresult rv = mBlock->SplitPlaceholder(*this, *fc->mPlaceholder); + nsresult rv = mBlock->SplitPlaceholder(*mPresContext, *fc->mPlaceholder); if (NS_FAILED(rv)) return PR_FALSE; } diff --git a/mozilla/layout/generic/nsBlockReflowState.h b/mozilla/layout/generic/nsBlockReflowState.h index 694b4230f9d..cfa639b5ba3 100644 --- a/mozilla/layout/generic/nsBlockReflowState.h +++ b/mozilla/layout/generic/nsBlockReflowState.h @@ -199,9 +199,6 @@ public: nsFloaterCacheFreeList mFloaterCacheFreeList; - // next-in-flows of incomplete floaters which get put into overflow lines - nsFrameList mOverflowFloaters; - // Previous child. This is used when pulling up a frame to update // the sibling list. nsIFrame* mPrevChild; diff --git a/mozilla/layout/generic/nsFrame.cpp b/mozilla/layout/generic/nsFrame.cpp index 7132d48b1fc..582c6857297 100644 --- a/mozilla/layout/generic/nsFrame.cpp +++ b/mozilla/layout/generic/nsFrame.cpp @@ -4621,6 +4621,54 @@ nsFrame::IsMouseCaptured(nsIPresContext* aPresContext) return PR_FALSE; } +nsresult +nsFrame::SetProperty(nsIPresContext* aPresContext, + nsIAtom* aPropName, + void* aPropValue, + NSFramePropertyDtorFunc aPropDtorFunc) +{ + nsCOMPtr presShell; + nsresult rv = NS_ERROR_FAILURE; + + aPresContext->GetShell(getter_AddRefs(presShell)); + if (presShell) { + nsCOMPtr frameManager; + presShell->GetFrameManager(getter_AddRefs(frameManager)); + + if (frameManager) { + rv = frameManager->SetFrameProperty(this, aPropName, aPropValue, aPropDtorFunc); + } + } + return rv; +} + +void* +nsFrame::GetProperty(nsIPresContext* aPresContext, + nsIAtom* aPropName, + PRBool aRemoveProp) const +{ + void* value = nsnull; + + nsCOMPtr presShell; + aPresContext->GetShell(getter_AddRefs(presShell)); + + if (presShell) { + nsCOMPtr frameManager; + presShell->GetFrameManager(getter_AddRefs(frameManager)); + + if (frameManager) { + PRUint32 options = 0; + + if (aRemoveProp) { + options |= NS_IFRAME_MGR_REMOVE_PROP; + } + frameManager->GetFrameProperty((nsIFrame*)this, aPropName, options, &value); + } + } + + return value; +} + #ifdef IBMBIDI /** * retrieve Bidi property of this frame diff --git a/mozilla/layout/generic/nsFrame.h b/mozilla/layout/generic/nsFrame.h index 84adffee80b..2a35962f237 100644 --- a/mozilla/layout/generic/nsFrame.h +++ b/mozilla/layout/generic/nsFrame.h @@ -386,6 +386,16 @@ public: //Mouse Capturing code used by the frames to tell the view to capture all the following events NS_IMETHOD CaptureMouse(nsIPresContext* aPresContext, PRBool aGrabMouseEvents); PRBool IsMouseCaptured(nsIPresContext* aPresContext); + + virtual void* GetProperty(nsIPresContext* aPresContext, + nsIAtom* aPropertyName, + PRBool aRemoveProperty) const; + + virtual nsresult SetProperty(nsIPresContext* aPresContext, + nsIAtom* aPropertyName, + void* aPropertyValue, + NSFramePropertyDtorFunc aPropDtorFunc); + #ifdef IBMBIDI NS_IMETHOD GetBidiProperty(nsIPresContext* aPresContext, nsIAtom* aPropertyName, diff --git a/mozilla/layout/generic/nsIFrame.h b/mozilla/layout/generic/nsIFrame.h index 1d2951186eb..b9de9beb248 100644 --- a/mozilla/layout/generic/nsIFrame.h +++ b/mozilla/layout/generic/nsIFrame.h @@ -90,6 +90,13 @@ struct nsRect; struct nsSize; struct nsMargin; +// Calback function used to destroy the value associated with a property. +typedef void +(*NSFramePropertyDtorFunc)(nsIPresContext* aPresContext, + nsIFrame* aFrame, + nsIAtom* aPropertyName, + void* aPropertyValue); + // IID for the nsIFrame interface // a6cf9050-15b3-11d2-932e-00805f8add32 #define NS_IFRAME_IID \ @@ -1158,6 +1165,14 @@ public: PRBool aIsPre, PRBool* aResult) = 0; + virtual void* GetProperty(nsIPresContext* aPresContext, + nsIAtom* aPropertyName, + PRBool aRemoveProperty) const = 0; + + virtual nsresult SetProperty(nsIPresContext* aPresContext, + nsIAtom* aPropertyName, + void* aPropertyValue, + NSFramePropertyDtorFunc aPropDtorFunc) = 0; #ifdef IBMBIDI /** * retrieve and set Bidi property of this frame diff --git a/mozilla/layout/generic/nsInlineFrame.cpp b/mozilla/layout/generic/nsInlineFrame.cpp index 444ffa6ed00..22ddff94fb1 100644 --- a/mozilla/layout/generic/nsInlineFrame.cpp +++ b/mozilla/layout/generic/nsInlineFrame.cpp @@ -779,7 +779,7 @@ nsInlineFrame::ReflowInlineFrame(nsIPresContext* aPresContext, aFrame->GetFrameType(getter_AddRefs(frameType)); if (nsLayoutAtoms::placeholderFrame == frameType) { nsBlockReflowState* blockRS = lineLayout->mBlockRS; - blockRS->mBlock->SplitPlaceholder(*blockRS, *aFrame); + blockRS->mBlock->SplitPlaceholder(*aPresContext, *aFrame); } else { nsIFrame* newFrame; diff --git a/mozilla/layout/html/base/src/nsBlockFrame.cpp b/mozilla/layout/html/base/src/nsBlockFrame.cpp index bd23d692fac..1611bfd6370 100644 --- a/mozilla/layout/html/base/src/nsBlockFrame.cpp +++ b/mozilla/layout/html/base/src/nsBlockFrame.cpp @@ -945,42 +945,78 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, NS_ASSERTION(NS_SUCCEEDED(rv), "reflow dirty lines failed"); if (NS_FAILED(rv)) return rv; - // Put continued floaters at the beginning of the first overflow line. If the first line - // is a block then create a new line as the first line and put the floaters there. If there - // are no overflow lines, then create one and put the floaters in it. - if (state.mOverflowFloaters.NotEmpty()) { - nsLineList* overflowLines = GetOverflowLines(aPresContext, PR_FALSE); - if (overflowLines) { - line_iterator firstLine = overflowLines->begin(); - if (firstLine->IsBlock()) { // floaters go on a new line before 1st overflow line - nsLineBox* newLine = state.NewLineBox(state.mOverflowFloaters.FirstChild(), - state.mOverflowFloaters.GetLength(), PR_FALSE); - firstLine = mLines.before_insert(firstLine, newLine); - } - else { // floaters go on 1st overflow line - nsIFrame* firstFrame = firstLine->mFirstChild; - firstLine->mFirstChild = state.mOverflowFloaters.FirstChild(); - PRInt32 numOverflowFloaters = state.mOverflowFloaters.GetLength(); - // hook up the last placeholder with the original frames - nsPlaceholderFrame* lastPlaceholder = - (nsPlaceholderFrame*)state.mOverflowFloaters.LastChild(); - lastPlaceholder->SetNextSibling(firstFrame); - NS_ASSERTION(firstFrame != lastPlaceholder, "trying to set next sibling to self"); - firstLine->SetChildCount(firstLine->GetChildCount() + numOverflowFloaters); + // If the block is complete, put continuted floaters in the closest ancestor + // block that uses the same space manager and leave the block complete; this + // allows subsequent lines on the page to be impacted by floaters. If the + // block is incomplete or there is no ancestor using the same space manager, + // put continued floaters at the beginning of the first overflow line. + nsFrameList* overflowPlace = nsnull; + if ((NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight) && + (overflowPlace = GetOverflowPlaceholders(aPresContext, PR_TRUE))) { + PRBool gaveToAncestor = PR_FALSE; + if (NS_FRAME_IS_COMPLETE(state.mReflowStatus)) { + // find the nearest block ancestor that uses the same space manager + for (const nsHTMLReflowState* ancestorRS = aReflowState.parentReflowState; + ancestorRS; + ancestorRS = ancestorRS->parentReflowState) { + nsIFrame* ancestor = ancestorRS->frame; + nsCOMPtr fType; + ancestor->GetFrameType(getter_AddRefs(fType)); + if ((nsLayoutAtoms::blockFrame == fType) || (nsLayoutAtoms::areaFrame == fType)) { + if (aReflowState.mSpaceManager == ancestorRS->mSpaceManager) { + // Put the continued floaters in ancestor since it uses the same space manager + nsFrameList* ancestorPlace = + ((nsBlockFrame*)ancestor)->GetOverflowPlaceholders(aPresContext, PR_FALSE); + if (ancestorPlace) { + ancestorPlace->AppendFrames(ancestor, overflowPlace->FirstChild()); + } + else { + ancestorPlace = new nsFrameList(overflowPlace->FirstChild()); + if (ancestorPlace) { + ((nsBlockFrame*)ancestor)->SetOverflowPlaceholders(aPresContext, ancestorPlace); + } + else + return NS_ERROR_OUT_OF_MEMORY; + } + gaveToAncestor = PR_TRUE; + break; + } + } } } - else { - // Create a line, put the floaters in it, and then push. - nsLineBox* newLine = state.NewLineBox(state.mOverflowFloaters.FirstChild(), - state.mOverflowFloaters.GetLength(), PR_FALSE); - if (!newLine) - return NS_ERROR_OUT_OF_MEMORY; - mLines.push_back(newLine); - nsLineList::iterator nextToLastLine = ----end_lines(); - PushLines(state, nextToLastLine); + if (!gaveToAncestor) { + PRInt32 numOverflowPlace = overflowPlace->GetLength(); + nsLineList* overflowLines = GetOverflowLines(aPresContext, PR_FALSE); + if (overflowLines) { + line_iterator firstLine = overflowLines->begin(); + if (firstLine->IsBlock()) { + // Create a new line as the first line and put the floaters there; + nsLineBox* newLine = state.NewLineBox(overflowPlace->FirstChild(), numOverflowPlace, PR_FALSE); + firstLine = mLines.before_insert(firstLine, newLine); + } + else { // floaters go on 1st overflow line + nsIFrame* firstFrame = firstLine->mFirstChild; + firstLine->mFirstChild = overflowPlace->FirstChild(); + // hook up the last placeholder with the original frames + nsPlaceholderFrame* lastPlaceholder = + (nsPlaceholderFrame*)overflowPlace->LastChild(); + lastPlaceholder->SetNextSibling(firstFrame); + NS_ASSERTION(firstFrame != lastPlaceholder, "trying to set next sibling to self"); + firstLine->SetChildCount(firstLine->GetChildCount() + numOverflowPlace); + } + } + else { + // Create a line, put the floaters in it, and then push. + nsLineBox* newLine = state.NewLineBox(overflowPlace->FirstChild(), numOverflowPlace, PR_FALSE); + if (!newLine) + return NS_ERROR_OUT_OF_MEMORY; + mLines.push_back(newLine); + nsLineList::iterator nextToLastLine = ----end_lines(); + PushLines(state, nextToLastLine); + } + state.mReflowStatus = NS_FRAME_NOT_COMPLETE; } - state.mReflowStatus = NS_FRAME_NOT_COMPLETE; - state.mOverflowFloaters.SetFrames(nsnull); + delete overflowPlace; } if (NS_FRAME_IS_NOT_COMPLETE(state.mReflowStatus)) { @@ -3151,9 +3187,9 @@ nsBlockFrame::GetTopBlockChild(nsIPresContext* aPresContext) // If placeholders/floaters split during reflowing a line, but that line will // be put on the next page, then put the placeholders/floaters back the way // they were before the line was reflowed. -static void -UndoPlaceholders(nsBlockReflowState& aState, - nsIFrame* aLastPlaceholder) +void +nsBlockFrame::UndoSplitPlaceholders(nsBlockReflowState& aState, + nsIFrame* aLastPlaceholder) { nsIFrame* undoPlaceholder = nsnull; if (aLastPlaceholder) { @@ -3161,8 +3197,9 @@ UndoPlaceholders(nsBlockReflowState& aState, aLastPlaceholder->SetNextSibling(nsnull); } else { - undoPlaceholder = aState.mOverflowFloaters.FirstChild(); - aState.mOverflowFloaters.SetFrames(nsnull); + // just remove the property + nsFrameList* overflowPlace = GetOverflowPlaceholders(aState.mPresContext, PR_TRUE); + delete overflowPlace; } // remove the next in flows of the placeholders that need to be removed for (nsIFrame* placeholder = undoPlaceholder; placeholder; ) { @@ -3320,7 +3357,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, } // keep track of the last overflow floater in case we need to undo any new additions - nsIFrame* lastPlaceholder = aState.mOverflowFloaters.LastChild(); + nsFrameList* overflowPlace = GetOverflowPlaceholders(aState.mPresContext, PR_FALSE); + nsIFrame* lastPlaceholder = (overflowPlace) ? overflowPlace->LastChild() : nsnull; // Reflow the block into the available space nsReflowStatus frameReflowStatus=NS_FRAME_COMPLETE; @@ -3353,7 +3391,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, if (NS_INLINE_IS_BREAK_BEFORE(frameReflowStatus)) { // None of the child block fits. - ::UndoPlaceholders(aState, lastPlaceholder); + UndoSplitPlaceholders(aState, lastPlaceholder); PushLines(aState, aLine.prev()); *aKeepReflowGoing = PR_FALSE; aState.mReflowStatus = NS_FRAME_NOT_COMPLETE; @@ -3530,7 +3568,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, else { // Push the line that didn't fit and any lines that follow it // to our next-in-flow. - ::UndoPlaceholders(aState, lastPlaceholder); + UndoSplitPlaceholders(aState, lastPlaceholder); PushLines(aState, aLine.prev()); aState.mReflowStatus = NS_FRAME_NOT_COMPLETE; } @@ -3644,7 +3682,7 @@ nsBlockFrame::PushTruncatedPlaceholderLine(nsBlockReflowState& aState, nsIFrame* aLastPlaceholder, PRBool& aKeepReflowGoing) { - ::UndoPlaceholders(aState, aLastPlaceholder); + UndoSplitPlaceholders(aState, aLastPlaceholder); line_iterator prevLine = aLine; --prevLine; @@ -3716,7 +3754,8 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState, } // keep track of the last overflow floater in case we need to undo any new additions - nsIFrame* lastPlaceholder = aState.mOverflowFloaters.LastChild(); + nsFrameList* overflowPlace = GetOverflowPlaceholders(aState.mPresContext, PR_FALSE); + nsIFrame* lastPlaceholder = (overflowPlace) ? overflowPlace->LastChild() : nsnull; // Reflow the frames that are already on the line first nsresult rv = NS_OK; @@ -3814,7 +3853,7 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState, // no point in placing the line. if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) { if (PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing, aUpdateMaximumWidth)) { - ::UndoPlaceholders(aState, lastPlaceholder); // undo since we pushed the current line + UndoSplitPlaceholders(aState, lastPlaceholder); // undo since we pushed the current line } } } @@ -3991,7 +4030,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState, // frame may already have a continuation. PRBool madeContinuation; rv = (nsLayoutAtoms::placeholderFrame == frameType) - ? SplitPlaceholder(aState, *aFrame) + ? SplitPlaceholder(*aState.mPresContext, *aFrame) : CreateContinuationFor(aState, aLine, aFrame, madeContinuation); if (NS_FAILED(rv)) return rv; @@ -4070,11 +4109,11 @@ nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState, } nsresult -nsBlockFrame::SplitPlaceholder(nsBlockReflowState& aState, - nsIFrame& aPlaceholder) +nsBlockFrame::SplitPlaceholder(nsIPresContext& aPresContext, + nsIFrame& aPlaceholder) { nsIFrame* nextInFlow; - nsresult rv = CreateNextInFlow(aState.mPresContext, this, &aPlaceholder, nextInFlow); + nsresult rv = CreateNextInFlow(&aPresContext, this, &aPlaceholder, nextInFlow); if (NS_FAILED(rv)) return rv; // put the sibling list back to what it was before the continuation was created @@ -4084,7 +4123,17 @@ nsBlockFrame::SplitPlaceholder(nsBlockReflowState& aState, aPlaceholder.SetNextSibling(next); contFrame->SetNextSibling(nsnull); // add the placehoder to the overflow floaters - aState.mOverflowFloaters.AppendFrames(this, contFrame); + nsFrameList* overflowPlace = GetOverflowPlaceholders(&aPresContext, PR_FALSE); + if (overflowPlace) { + overflowPlace->AppendFrames(this, contFrame); + } + else { + overflowPlace = new nsFrameList(contFrame); + if (overflowPlace) { + SetOverflowPlaceholders(&aPresContext, overflowPlace); + } + else return NS_ERROR_NULL_POINTER; + } return NS_OK; } @@ -4415,7 +4464,8 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, // Any below current line floaters to place? if (aState.mBelowCurrentLineFloaters.NotEmpty()) { // keep track of the last overflow floater in case we need to undo and push the line - nsIFrame* lastPlaceholder = aState.mOverflowFloaters.LastChild(); + nsFrameList* overflowPlace = GetOverflowPlaceholders(aState.mPresContext, PR_FALSE); + nsIFrame* lastPlaceholder = (overflowPlace) ? overflowPlace->LastChild() : nsnull; // Reflow the below-current-line floaters, then add them to the // lines floater list if there aren't any truncated floaters. if (aState.PlaceBelowCurrentLineFloaters(aState.mBelowCurrentLineFloaters)) { @@ -4739,31 +4789,12 @@ nsLineList* nsBlockFrame::GetOverflowLines(nsIPresContext* aPresContext, PRBool aRemoveProperty) const { - nsCOMPtr presShell; - aPresContext->GetShell(getter_AddRefs(presShell)); - - if (presShell) { - nsCOMPtr frameManager; - presShell->GetFrameManager(getter_AddRefs(frameManager)); - - if (frameManager) { - PRUint32 options = 0; - nsLineList* value; - - if (aRemoveProperty) { - options |= NS_IFRAME_MGR_REMOVE_PROP; - } - frameManager->GetFrameProperty(NS_CONST_CAST(nsBlockFrame*, this), - nsLayoutAtoms::overflowLinesProperty, - options, - NS_REINTERPRET_CAST(void**, &value)); - NS_ASSERTION(!value || !value->empty(), - "value should never be stored as empty"); - return value; - } - } - - return nsnull; + nsLineList* lines = + NS_STATIC_CAST(nsLineList*, GetProperty(aPresContext, + nsLayoutAtoms::overflowLinesProperty, + aRemoveProperty)); + NS_ASSERTION(!lines || !lines->empty(), "value should never be stored as empty"); + return lines; } // Destructor function for the overflowLines frame property @@ -4786,27 +4817,48 @@ nsresult nsBlockFrame::SetOverflowLines(nsIPresContext* aPresContext, nsLineList* aOverflowLines) { - nsCOMPtr presShell; - nsresult rv = NS_ERROR_FAILURE; - NS_ASSERTION(aOverflowLines, "null lines"); - NS_ASSERTION(! aOverflowLines->empty(), "empty lines"); + NS_ASSERTION(!aOverflowLines->empty(), "empty lines"); - aPresContext->GetShell(getter_AddRefs(presShell)); - if (presShell) { - nsCOMPtr frameManager; - presShell->GetFrameManager(getter_AddRefs(frameManager)); - - if (frameManager) { - rv = frameManager->SetFrameProperty(this, - nsLayoutAtoms::overflowLinesProperty, - aOverflowLines, - DestroyOverflowLines); + nsresult rv = SetProperty(aPresContext, nsLayoutAtoms::overflowLinesProperty, + aOverflowLines, DestroyOverflowLines); + // Verify that we didn't overwrite an existing overflow list + NS_ASSERTION(rv != NS_IFRAME_MGR_PROP_OVERWRITTEN, "existing overflow list"); + return rv; +} - // Verify that we didn't overwrite an existing overflow list - NS_ASSERTION(rv != NS_IFRAME_MGR_PROP_OVERWRITTEN, "existing overflow list"); - } - } +nsFrameList* +nsBlockFrame::GetOverflowPlaceholders(nsIPresContext* aPresContext, + PRBool aRemoveProperty) const +{ + nsFrameList* placeholders = + NS_STATIC_CAST(nsFrameList*, + GetProperty(aPresContext, nsLayoutAtoms::overflowPlaceholdersProperty, + aRemoveProperty)); + return placeholders; +} + +// Destructor function for the overflowPlaceholders frame property +static void +DestroyOverflowPlaceholders(nsIPresContext* aPresContext, + nsIFrame* aFrame, + nsIAtom* aPropertyName, + void* aPropertyValue) +{ + nsFrameList* overflowPlace = NS_STATIC_CAST(nsFrameList*, aPropertyValue); + delete overflowPlace; +} + +// This takes ownership of aOverflowLines. +// XXX We should allocate overflowLines from presShell arena! +nsresult +nsBlockFrame::SetOverflowPlaceholders(nsIPresContext* aPresContext, + nsFrameList* aOverflowPlaceholders) +{ + nsresult rv = SetProperty(aPresContext, nsLayoutAtoms::overflowPlaceholdersProperty, + aOverflowPlaceholders, DestroyOverflowPlaceholders); + // Verify that we didn't overwrite an existing overflow list + NS_ASSERTION(rv != NS_IFRAME_MGR_PROP_OVERWRITTEN, "existing overflow placeholder list"); return rv; } diff --git a/mozilla/layout/html/base/src/nsBlockFrame.h b/mozilla/layout/html/base/src/nsBlockFrame.h index e6c419febdd..81f9d5ae5bb 100644 --- a/mozilla/layout/html/base/src/nsBlockFrame.h +++ b/mozilla/layout/html/base/src/nsBlockFrame.h @@ -201,9 +201,11 @@ public: // Create a contination for aPlaceholder and its out of flow frame and // add it to the list of overflow floaters - nsresult SplitPlaceholder(nsBlockReflowState& aState, - nsIFrame& aPlaceholder); + nsresult SplitPlaceholder(nsIPresContext& aPresContext, nsIFrame& aPlaceholder); + void UndoSplitPlaceholders(nsBlockReflowState& aState, + nsIFrame* aLastPlaceholder); + protected: nsBlockFrame(); virtual ~nsBlockFrame(); @@ -503,6 +505,12 @@ protected: nsresult SetOverflowLines(nsIPresContext* aPresContext, nsLineList* aOverflowLines); + nsFrameList* GetOverflowPlaceholders(nsIPresContext* aPresContext, + PRBool aRemoveProperty) const; + + nsresult SetOverflowPlaceholders(nsIPresContext* aPresContext, + nsFrameList* aOverflowPlaceholders); + nsIFrame* LastChild(); #ifdef NS_DEBUG diff --git a/mozilla/layout/html/base/src/nsBlockReflowState.cpp b/mozilla/layout/html/base/src/nsBlockReflowState.cpp index 84dcf843c4b..1f5558cf6df 100644 --- a/mozilla/layout/html/base/src/nsBlockReflowState.cpp +++ b/mozilla/layout/html/base/src/nsBlockReflowState.cpp @@ -46,6 +46,7 @@ #include "nsIPresContext.h" #include "nsLayoutAtoms.h" #include "nsIFrame.h" +#include "nsIFrameManager.h" #include "nsINameSpaceManager.h" #include "nsHTMLAtoms.h" @@ -124,7 +125,6 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, } } mHaveRightFloaters = PR_FALSE; - mOverflowFloaters.SetFrames(nsnull); // Compute content area height. Unlike the width, if we have a // specified style height we ignore it since extra content is @@ -847,7 +847,8 @@ nsBlockReflowState::FlowAndPlaceFloater(nsFloaterCache* aFloaterCache, // content. nscoord saveY = mY; - nsIFrame* floater = aFloaterCache->mPlaceholder->GetOutOfFlowFrame(); + nsPlaceholderFrame* placeholder = aFloaterCache->mPlaceholder; + nsIFrame* floater = placeholder->GetOutOfFlowFrame(); // Grab the floater's display information const nsStyleDisplay* floaterDisplay; @@ -879,8 +880,8 @@ nsBlockReflowState::FlowAndPlaceFloater(nsFloaterCache* aFloaterCache, } // Reflow the floater - mBlock->ReflowFloater(*this, aFloaterCache->mPlaceholder, aFloaterCache->mCombinedArea, - aFloaterCache->mMargins, aFloaterCache->mOffsets, aReflowStatus); + mBlock->ReflowFloater(*this, placeholder, aFloaterCache->mCombinedArea, + aFloaterCache->mMargins, aFloaterCache->mOffsets, aReflowStatus); // Get the floaters bounding box and margin information floater->GetRect(region); @@ -963,7 +964,7 @@ nsBlockReflowState::FlowAndPlaceFloater(nsFloaterCache* aFloaterCache, mY += mAvailSpaceRect.height; GetAvailableSpace(); // reflow the floater again now since we have more space - mBlock->ReflowFloater(*this, aFloaterCache->mPlaceholder, aFloaterCache->mCombinedArea, + mBlock->ReflowFloater(*this, placeholder, aFloaterCache->mCombinedArea, aFloaterCache->mMargins, aFloaterCache->mOffsets, aReflowStatus); // Get the floaters bounding box and margin information floater->GetRect(region); @@ -974,12 +975,33 @@ nsBlockReflowState::FlowAndPlaceFloater(nsFloaterCache* aFloaterCache, } } - // If the floater is continued, it will get the same x value as its prev-in-flow - nsRect prevInFlowRect(0,0,0,0); + // If the floater is continued, it will get the same absolute x value as its prev-in-flow + nsRect prevRect(0,0,0,0); nsIFrame* prevInFlow; floater->GetPrevInFlow(&prevInFlow); if (prevInFlow) { - prevInFlow->GetRect(prevInFlowRect); + prevInFlow->GetRect(prevRect); + + nsCOMPtr presShell; + mPresContext->GetShell(getter_AddRefs(presShell)); + nsCOMPtr frameManager; + presShell->GetFrameManager(getter_AddRefs(frameManager)); + + nsIFrame *placeParent, *placeParentPrev, *prevPlace, *prevPlaceParent; + // If prevInFlow's placeholder is in a block that wasn't continued, we need to adjust + // prevRect.x to account for the missing frame offsets. + placeholder->GetParent(&placeParent); + placeParent->GetPrevInFlow(&placeParentPrev); + frameManager->GetPlaceholderFrameFor(prevInFlow, &prevPlace); + prevPlace->GetParent(&prevPlaceParent); + + for (nsIFrame* ancestor = prevPlaceParent; + ancestor && (ancestor != placeParentPrev); + ancestor->GetParent(&ancestor)) { + nsRect rect; + ancestor->GetRect(rect); + prevRect.x += rect.x; + } } // Assign an x and y coordinate to the floater. Note that the x,y // coordinates are computed relative to the translation in the @@ -989,7 +1011,7 @@ nsBlockReflowState::FlowAndPlaceFloater(nsFloaterCache* aFloaterCache, PRBool isLeftFloater; if (NS_STYLE_FLOAT_LEFT == floaterDisplay->mFloats) { isLeftFloater = PR_TRUE; - region.x = (prevInFlow) ? prevInFlowRect.x : mAvailSpaceRect.x; + region.x = (prevInFlow) ? prevRect.x : mAvailSpaceRect.x; } else { isLeftFloater = PR_FALSE; @@ -997,7 +1019,7 @@ nsBlockReflowState::FlowAndPlaceFloater(nsFloaterCache* aFloaterCache, nsIFrame* prevInFlow; floater->GetPrevInFlow(&prevInFlow); if (prevInFlow) { - region.x = prevInFlowRect.x; + region.x = prevRect.x; } else if (!keepFloaterOnSameLine) { region.x = mAvailSpaceRect.XMost() - region.width; @@ -1030,7 +1052,7 @@ nsBlockReflowState::FlowAndPlaceFloater(nsFloaterCache* aFloaterCache, // if the floater split, then take up all of the vertical height if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus) && (NS_UNCONSTRAINEDSIZE != mContentArea.height)) { - region.height += PR_MAX(region.height, mContentArea.height); + region.height = PR_MAX(region.height, mContentArea.height); } #ifdef DEBUG nsresult rv = @@ -1160,7 +1182,7 @@ nsBlockReflowState::PlaceBelowCurrentLineFloaters(nsFloaterCacheList& aList) } else if (NS_FRAME_IS_NOT_COMPLETE(reflowStatus)) { // Create a continuation for the incomplete floater and its placeholder. - nsresult rv = mBlock->SplitPlaceholder(*this, *fc->mPlaceholder); + nsresult rv = mBlock->SplitPlaceholder(*mPresContext, *fc->mPlaceholder); if (NS_FAILED(rv)) return PR_FALSE; } diff --git a/mozilla/layout/html/base/src/nsBlockReflowState.h b/mozilla/layout/html/base/src/nsBlockReflowState.h index 694b4230f9d..cfa639b5ba3 100644 --- a/mozilla/layout/html/base/src/nsBlockReflowState.h +++ b/mozilla/layout/html/base/src/nsBlockReflowState.h @@ -199,9 +199,6 @@ public: nsFloaterCacheFreeList mFloaterCacheFreeList; - // next-in-flows of incomplete floaters which get put into overflow lines - nsFrameList mOverflowFloaters; - // Previous child. This is used when pulling up a frame to update // the sibling list. nsIFrame* mPrevChild; diff --git a/mozilla/layout/html/base/src/nsFrame.cpp b/mozilla/layout/html/base/src/nsFrame.cpp index 7132d48b1fc..582c6857297 100644 --- a/mozilla/layout/html/base/src/nsFrame.cpp +++ b/mozilla/layout/html/base/src/nsFrame.cpp @@ -4621,6 +4621,54 @@ nsFrame::IsMouseCaptured(nsIPresContext* aPresContext) return PR_FALSE; } +nsresult +nsFrame::SetProperty(nsIPresContext* aPresContext, + nsIAtom* aPropName, + void* aPropValue, + NSFramePropertyDtorFunc aPropDtorFunc) +{ + nsCOMPtr presShell; + nsresult rv = NS_ERROR_FAILURE; + + aPresContext->GetShell(getter_AddRefs(presShell)); + if (presShell) { + nsCOMPtr frameManager; + presShell->GetFrameManager(getter_AddRefs(frameManager)); + + if (frameManager) { + rv = frameManager->SetFrameProperty(this, aPropName, aPropValue, aPropDtorFunc); + } + } + return rv; +} + +void* +nsFrame::GetProperty(nsIPresContext* aPresContext, + nsIAtom* aPropName, + PRBool aRemoveProp) const +{ + void* value = nsnull; + + nsCOMPtr presShell; + aPresContext->GetShell(getter_AddRefs(presShell)); + + if (presShell) { + nsCOMPtr frameManager; + presShell->GetFrameManager(getter_AddRefs(frameManager)); + + if (frameManager) { + PRUint32 options = 0; + + if (aRemoveProp) { + options |= NS_IFRAME_MGR_REMOVE_PROP; + } + frameManager->GetFrameProperty((nsIFrame*)this, aPropName, options, &value); + } + } + + return value; +} + #ifdef IBMBIDI /** * retrieve Bidi property of this frame diff --git a/mozilla/layout/html/base/src/nsFrame.h b/mozilla/layout/html/base/src/nsFrame.h index 84adffee80b..2a35962f237 100644 --- a/mozilla/layout/html/base/src/nsFrame.h +++ b/mozilla/layout/html/base/src/nsFrame.h @@ -386,6 +386,16 @@ public: //Mouse Capturing code used by the frames to tell the view to capture all the following events NS_IMETHOD CaptureMouse(nsIPresContext* aPresContext, PRBool aGrabMouseEvents); PRBool IsMouseCaptured(nsIPresContext* aPresContext); + + virtual void* GetProperty(nsIPresContext* aPresContext, + nsIAtom* aPropertyName, + PRBool aRemoveProperty) const; + + virtual nsresult SetProperty(nsIPresContext* aPresContext, + nsIAtom* aPropertyName, + void* aPropertyValue, + NSFramePropertyDtorFunc aPropDtorFunc); + #ifdef IBMBIDI NS_IMETHOD GetBidiProperty(nsIPresContext* aPresContext, nsIAtom* aPropertyName, diff --git a/mozilla/layout/html/base/src/nsFrameManager.cpp b/mozilla/layout/html/base/src/nsFrameManager.cpp index b020a6a7849..11e4f45afd1 100644 --- a/mozilla/layout/html/base/src/nsFrameManager.cpp +++ b/mozilla/layout/html/base/src/nsFrameManager.cpp @@ -371,10 +371,10 @@ public: nsIAtom* aPropertyName, PRUint32 aOptions, void** aPropertyValue); - NS_IMETHOD SetFrameProperty(nsIFrame* aFrame, - nsIAtom* aPropertyName, - void* aPropertyValue, - NSFMPropertyDtorFunc aPropDtorFunc); + NS_IMETHOD SetFrameProperty(nsIFrame* aFrame, + nsIAtom* aPropertyName, + void* aPropertyValue, + NSFramePropertyDtorFunc aPropDtorFunc); NS_IMETHOD RemoveFrameProperty(nsIFrame* aFrame, nsIAtom* aPropertyName); @@ -383,13 +383,13 @@ public: #endif struct PropertyList { - nsCOMPtr mName; // property name - PLDHashTable mFrameValueMap; // map of frame/value pairs - NSFMPropertyDtorFunc mDtorFunc; // property specific value dtor function - PropertyList* mNext; + nsCOMPtr mName; // property name + PLDHashTable mFrameValueMap; // map of frame/value pairs + NSFramePropertyDtorFunc mDtorFunc; // property specific value dtor function + PropertyList* mNext; - PropertyList(nsIAtom* aName, - NSFMPropertyDtorFunc aDtorFunc); + PropertyList(nsIAtom* aName, + NSFramePropertyDtorFunc aDtorFunc); ~PropertyList(); // Removes the property associated with the given frame, and destroys @@ -2452,10 +2452,10 @@ FrameManager::GetFrameProperty(nsIFrame* aFrame, } NS_IMETHODIMP -FrameManager::SetFrameProperty(nsIFrame* aFrame, - nsIAtom* aPropertyName, - void* aPropertyValue, - NSFMPropertyDtorFunc aPropDtorFunc) +FrameManager::SetFrameProperty(nsIFrame* aFrame, + nsIAtom* aPropertyName, + void* aPropertyValue, + NSFramePropertyDtorFunc aPropDtorFunc) { NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_AVAILABLE); NS_PRECONDITION(aPropertyName && aFrame, "unexpected null param"); @@ -2667,8 +2667,8 @@ UndisplayedMap::Clear(void) //---------------------------------------------------------------------- -FrameManager::PropertyList::PropertyList(nsIAtom* aName, - NSFMPropertyDtorFunc aDtorFunc) +FrameManager::PropertyList::PropertyList(nsIAtom* aName, + NSFramePropertyDtorFunc aDtorFunc) : mName(aName), mDtorFunc(aDtorFunc), mNext(nsnull) { PL_DHashTableInit(&mFrameValueMap, PL_DHashGetStubOps(), this, diff --git a/mozilla/layout/html/base/src/nsInlineFrame.cpp b/mozilla/layout/html/base/src/nsInlineFrame.cpp index 444ffa6ed00..22ddff94fb1 100644 --- a/mozilla/layout/html/base/src/nsInlineFrame.cpp +++ b/mozilla/layout/html/base/src/nsInlineFrame.cpp @@ -779,7 +779,7 @@ nsInlineFrame::ReflowInlineFrame(nsIPresContext* aPresContext, aFrame->GetFrameType(getter_AddRefs(frameType)); if (nsLayoutAtoms::placeholderFrame == frameType) { nsBlockReflowState* blockRS = lineLayout->mBlockRS; - blockRS->mBlock->SplitPlaceholder(*blockRS, *aFrame); + blockRS->mBlock->SplitPlaceholder(*aPresContext, *aFrame); } else { nsIFrame* newFrame; diff --git a/mozilla/layout/html/table/src/nsTableFrame.cpp b/mozilla/layout/html/table/src/nsTableFrame.cpp index df0b0372806..1b54fb3926e 100644 --- a/mozilla/layout/html/table/src/nsTableFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableFrame.cpp @@ -7412,7 +7412,7 @@ nsTableFrame::GetProperty(nsIPresContext* aPresContext, // The property isn't set yet, so allocate a new value, set the property, // and return the newly allocated value void* value = nsnull; - NSFMPropertyDtorFunc dtorFunc = nsnull; + NSFramePropertyDtorFunc dtorFunc = nsnull; if (aPropertyName == nsLayoutAtoms::collapseOffsetProperty) { value = new nsPoint(0, 0); dtorFunc = DestroyPointFunc; diff --git a/mozilla/layout/tables/nsTableFrame.cpp b/mozilla/layout/tables/nsTableFrame.cpp index df0b0372806..1b54fb3926e 100644 --- a/mozilla/layout/tables/nsTableFrame.cpp +++ b/mozilla/layout/tables/nsTableFrame.cpp @@ -7412,7 +7412,7 @@ nsTableFrame::GetProperty(nsIPresContext* aPresContext, // The property isn't set yet, so allocate a new value, set the property, // and return the newly allocated value void* value = nsnull; - NSFMPropertyDtorFunc dtorFunc = nsnull; + NSFramePropertyDtorFunc dtorFunc = nsnull; if (aPropertyName == nsLayoutAtoms::collapseOffsetProperty) { value = new nsPoint(0, 0); dtorFunc = DestroyPointFunc;