diff --git a/layout/forms/nsHTMLButtonControlFrame.cpp b/layout/forms/nsHTMLButtonControlFrame.cpp index b5b48d6df7be..cfb6a2f044d9 100644 --- a/layout/forms/nsHTMLButtonControlFrame.cpp +++ b/layout/forms/nsHTMLButtonControlFrame.cpp @@ -445,12 +445,13 @@ nsHTMLButtonControlFrame::Reflow(nsIPresContext& aPresContext, // reflow the child nsIFrame* firstKid = mFrames.FirstChild(); - nsSize availSize(aReflowState.mComputedWidth, aReflowState.mComputedHeight); + nsSize availSize(aReflowState.mComputedWidth, NS_INTRINSICSIZE); // indent the child inside us by the the focus border. We must do this separate from the // regular border. nsMargin focusPadding = mRenderer.GetAddedButtonBorderAndPadding(); + if (NS_INTRINSICSIZE != availSize.width) { availSize.width -= focusPadding.left + focusPadding.right; availSize.width = PR_MAX(availSize.width,0); @@ -459,8 +460,10 @@ nsHTMLButtonControlFrame::Reflow(nsIPresContext& aPresContext, availSize.height -= focusPadding.top + focusPadding.bottom; availSize.height = PR_MAX(availSize.height,0); } - + nsHTMLReflowState reflowState(aPresContext, aReflowState, firstKid, availSize); + //reflowState.computedWidth = availSize; + // XXX remove the following when the reflow state is fixed //ButtonHack(reflowState, "html4 button's area"); @@ -471,7 +474,8 @@ nsHTMLButtonControlFrame::Reflow(nsIPresContext& aPresContext, // See if it's targeted at us aReflowState.reflowCommand->GetTarget(targetFrame); if (this == targetFrame) { - // XXX Handle this... + Invalidate(nsRect(0,0,mRect.width,mRect.height), PR_FALSE); + reflowState.reason = eReflowReason_Resize; } else { nsIFrame* nextFrame; @@ -487,9 +491,16 @@ nsHTMLButtonControlFrame::Reflow(nsIPresContext& aPresContext, nsRect rect = nsRect(focusPadding.left + aReflowState.mComputedBorderPadding.left, focusPadding.top + aReflowState.mComputedBorderPadding.top, aDesiredSize.width, aDesiredSize.height); firstKid->SetRect(rect); - // add in our border and padding to the size of the child - aDesiredSize.width += focusPadding.left + focusPadding.right; - aDesiredSize.height += focusPadding.top + focusPadding.bottom; + // if computed use the computed values. + if (aReflowState.mComputedWidth != NS_INTRINSICSIZE && (aDesiredSize.width < aReflowState.mComputedWidth)) + aDesiredSize.width = aReflowState.mComputedWidth; + else + aDesiredSize.width += focusPadding.left + focusPadding.right; + + if (aReflowState.mComputedHeight != NS_INTRINSICSIZE && (aDesiredSize.height < aReflowState.mComputedHeight)) + aDesiredSize.height = aReflowState.mComputedHeight; + else + aDesiredSize.height += focusPadding.top + focusPadding.bottom; aDesiredSize.width += aReflowState.mComputedBorderPadding.left + aReflowState.mComputedBorderPadding.right; aDesiredSize.height += aReflowState.mComputedBorderPadding.top + aReflowState.mComputedBorderPadding.bottom; @@ -502,6 +513,7 @@ nsHTMLButtonControlFrame::Reflow(nsIPresContext& aPresContext, aDesiredSize.ascent = aDesiredSize.height; aDesiredSize.descent = 0; + aStatus = NS_FRAME_COMPLETE; return NS_OK; } diff --git a/layout/html/forms/src/nsHTMLButtonControlFrame.cpp b/layout/html/forms/src/nsHTMLButtonControlFrame.cpp index b5b48d6df7be..cfb6a2f044d9 100644 --- a/layout/html/forms/src/nsHTMLButtonControlFrame.cpp +++ b/layout/html/forms/src/nsHTMLButtonControlFrame.cpp @@ -445,12 +445,13 @@ nsHTMLButtonControlFrame::Reflow(nsIPresContext& aPresContext, // reflow the child nsIFrame* firstKid = mFrames.FirstChild(); - nsSize availSize(aReflowState.mComputedWidth, aReflowState.mComputedHeight); + nsSize availSize(aReflowState.mComputedWidth, NS_INTRINSICSIZE); // indent the child inside us by the the focus border. We must do this separate from the // regular border. nsMargin focusPadding = mRenderer.GetAddedButtonBorderAndPadding(); + if (NS_INTRINSICSIZE != availSize.width) { availSize.width -= focusPadding.left + focusPadding.right; availSize.width = PR_MAX(availSize.width,0); @@ -459,8 +460,10 @@ nsHTMLButtonControlFrame::Reflow(nsIPresContext& aPresContext, availSize.height -= focusPadding.top + focusPadding.bottom; availSize.height = PR_MAX(availSize.height,0); } - + nsHTMLReflowState reflowState(aPresContext, aReflowState, firstKid, availSize); + //reflowState.computedWidth = availSize; + // XXX remove the following when the reflow state is fixed //ButtonHack(reflowState, "html4 button's area"); @@ -471,7 +474,8 @@ nsHTMLButtonControlFrame::Reflow(nsIPresContext& aPresContext, // See if it's targeted at us aReflowState.reflowCommand->GetTarget(targetFrame); if (this == targetFrame) { - // XXX Handle this... + Invalidate(nsRect(0,0,mRect.width,mRect.height), PR_FALSE); + reflowState.reason = eReflowReason_Resize; } else { nsIFrame* nextFrame; @@ -487,9 +491,16 @@ nsHTMLButtonControlFrame::Reflow(nsIPresContext& aPresContext, nsRect rect = nsRect(focusPadding.left + aReflowState.mComputedBorderPadding.left, focusPadding.top + aReflowState.mComputedBorderPadding.top, aDesiredSize.width, aDesiredSize.height); firstKid->SetRect(rect); - // add in our border and padding to the size of the child - aDesiredSize.width += focusPadding.left + focusPadding.right; - aDesiredSize.height += focusPadding.top + focusPadding.bottom; + // if computed use the computed values. + if (aReflowState.mComputedWidth != NS_INTRINSICSIZE && (aDesiredSize.width < aReflowState.mComputedWidth)) + aDesiredSize.width = aReflowState.mComputedWidth; + else + aDesiredSize.width += focusPadding.left + focusPadding.right; + + if (aReflowState.mComputedHeight != NS_INTRINSICSIZE && (aDesiredSize.height < aReflowState.mComputedHeight)) + aDesiredSize.height = aReflowState.mComputedHeight; + else + aDesiredSize.height += focusPadding.top + focusPadding.bottom; aDesiredSize.width += aReflowState.mComputedBorderPadding.left + aReflowState.mComputedBorderPadding.right; aDesiredSize.height += aReflowState.mComputedBorderPadding.top + aReflowState.mComputedBorderPadding.bottom; @@ -502,6 +513,7 @@ nsHTMLButtonControlFrame::Reflow(nsIPresContext& aPresContext, aDesiredSize.ascent = aDesiredSize.height; aDesiredSize.descent = 0; + aStatus = NS_FRAME_COMPLETE; return NS_OK; } diff --git a/layout/xul/base/src/nsBoxFrame.cpp b/layout/xul/base/src/nsBoxFrame.cpp index a056981c3192..f68da1df62d0 100644 --- a/layout/xul/base/src/nsBoxFrame.cpp +++ b/layout/xul/base/src/nsBoxFrame.cpp @@ -40,6 +40,8 @@ #include "nsIViewManager.h" #define CONSTANT float(0.0) +#define DEBUG_REFLOW 0 +#define DEBUG_REDRAW 0 nsresult NS_NewBoxFrame ( nsIFrame** aNewFrame, PRUint32 aFlags ) @@ -107,12 +109,10 @@ nsBoxFrame::GetRedefinedMinPrefMax(nsIFrame* aFrame, nsBoxInfo& aSize) // see if the width or height was specifically set if (position->mWidth.GetUnit() == eStyleUnit_Coord) { aSize.prefSize.width = position->mWidth.GetCoordValue(); - aSize.prefWidthIntrinsic = PR_FALSE; } if (position->mHeight.GetUnit() == eStyleUnit_Coord) { aSize.prefSize.height = position->mHeight.GetCoordValue(); - aSize.prefHeightIntrinsic = PR_FALSE; } // same for min size. Unfortunately min size is always set to 0. So for now @@ -179,12 +179,52 @@ nsBoxFrame::GetChildBoxInfo(nsIPresContext& aPresContext, const nsHTMLReflowStat return NS_OK; } - // set the pref width and height to be intrinsic. - aSize.prefWidthIntrinsic = PR_TRUE; - aSize.prefHeightIntrinsic = PR_TRUE; + // start the preferred size as intrinsic + aSize.prefSize.width = NS_INTRINSICSIZE; + aSize.prefSize.height = NS_INTRINSICSIZE; + // redefine anything depending on css GetRedefinedMinPrefMax(aFrame, aSize); + // subtract out the childs margin and border + const nsStyleSpacing* spacing; + nsresult rv = aFrame->GetStyleData(eStyleStruct_Spacing, + (const nsStyleStruct*&) spacing); + + nsMargin margin; + spacing->GetMargin(margin); + nsMargin border; + spacing->GetBorderPadding(border); + nsMargin total = margin + border; + + // add in childs margin and border + if (aSize.prefSize.height != NS_INTRINSICSIZE) + aSize.prefSize.height += (total.left + total.right); + + if (aSize.prefSize.height != NS_INTRINSICSIZE) + aSize.prefSize.height += (total.top + total.bottom); + + // flow child at preferred size + nsHTMLReflowMetrics desiredSize(nsnull); + + nsCalculatedBoxInfo info(aSize); + + info.calculatedSize = aSize.prefSize; + + nsReflowStatus status; + PRBool redraw; + nsString reason("To get pref size"); + FlowChildAt(aFrame, aPresContext, desiredSize, aReflowState, status, info, redraw, reason); + + // remove margin and border + desiredSize.height -= (total.top + total.bottom); + desiredSize.width -= (total.left + total.right); + + // get the size returned and the it as the preferredsize. + aSize.prefSize.width = desiredSize.width; + aSize.prefSize.height = desiredSize.height; + + return NS_OK; } @@ -204,6 +244,12 @@ nsBoxFrame::Reflow(nsIPresContext& aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { + +#if DEBUG_REFLOW + if (NS_BLOCK_DOCUMENT_ROOT & mFlags) + printf("---------------- Begin Reflow ---------------\n"); +#endif + // If we have a space manager, then set it in the reflow state if (mSpaceManager) { // Modify the reflow state and set the space manager @@ -282,7 +328,7 @@ printf("\n"); //----------------------------------------------------------------------------------- // flow each child at the new sizes we have calculated. - FlowChildren(aPresContext, aDesiredSize, aReflowState, aStatus, rect, incrementalChild); + FlowChildren(aPresContext, aDesiredSize, aReflowState, aStatus, rect); //----------------------------------------------------------------------------------- //------------------------- Adjust each childs x, y location------------------------- @@ -312,9 +358,9 @@ printf("\n"); damageArea.height = aDesiredSize.height; damageArea.width = aDesiredSize.width; - if ((NS_BLOCK_DOCUMENT_ROOT & mFlags) && !damageArea.IsEmpty()) { - Invalidate(damageArea); - } + // if ((NS_BLOCK_DOCUMENT_ROOT & mFlags) && !damageArea.IsEmpty()) { + // Invalidate(damageArea); + // } #if 0 ListTag(stdout); printf(": reflow done\n"); #endif @@ -332,22 +378,26 @@ nsBoxFrame::FlowChildren(nsIPresContext& aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus, - nsRect& rect, - nsIFrame*& incrementalChild) + nsRect& rect) { + PRBool redraw = PR_FALSE; + //----------------------------------- // first pass flow all fixed children //----------------------------------- - PRBool resized[100]; - int i; - for (i=0; i < mSpringCount; i++) - resized[i] = PR_FALSE; - PRBool finished; nscoord passes = 0; nscoord changedIndex = -1; nscoord count = 0; + nsString reason="initial"; + nsString nextReason = "initial"; + PRBool resized[100]; + + for (int i=0; i < mSpringCount; i++) + resized[i] = PR_FALSE; + + /* nsIFrame* childFrame = mFrames.FirstChild(); while (nsnull != childFrame) { @@ -356,20 +406,25 @@ nsBoxFrame::FlowChildren(nsIPresContext& aPresContext, { // reflow only fixed children if (mSprings[count].flex == 0.0) { - FlowChildAt(childFrame, aPresContext, aDesiredSize, aReflowState, aStatus, count, incrementalChild); + FlowChildAt(childFrame, aPresContext, aDesiredSize, aReflowState, aStatus, mSprings[count], redraw, reason); // if its height greater than the max. Set the max to this height and set a flag // saying we will need to do another pass. But keep going there // may be another child that is bigger - if (!mHorizontal) { - if (rect.height == NS_INTRINSICSIZE || aDesiredSize.height > mSprings[count].calculatedSize.height) { - mSprings[count].calculatedSize.height = aDesiredSize.height; - resized[count] = PR_TRUE; + if (mHorizontal) { + if (aDesiredSize.height > rect.height) { + rect.height = aDesiredSize.height; + InvalidateChildren(); + LayoutChildrenInRect(rect); + nextReason = "child's height got bigger"; } } else { - if (rect.width == NS_INTRINSICSIZE || aDesiredSize.width > mSprings[count].calculatedSize.width) { - mSprings[count].calculatedSize.width = aDesiredSize.width; - resized[count] = PR_TRUE; + if (aDesiredSize.width > rect.width) { + mSprings[count].minSize.width = aDesiredSize.width; + rect.width = aDesiredSize.width; + InvalidateChildren(); + LayoutChildrenInRect(rect); + nextReason = "child's width got bigger"; } } } @@ -378,6 +433,9 @@ nsBoxFrame::FlowChildren(nsIPresContext& aPresContext, NS_ASSERTION(rv == NS_OK,"failed to get next child"); count++; } + */ + + //reason = nextReason; // ---------------------- @@ -391,12 +449,8 @@ nsBoxFrame::FlowChildren(nsIPresContext& aPresContext, changedIndex = -1; InvalidateChildren(); - - for (i=0; i < mSpringCount; i++) - mSprings[i].sizeValid = resized[i]; - LayoutChildrenInRect(rect); - + passes = 0; do { @@ -412,66 +466,17 @@ nsBoxFrame::FlowChildren(nsIPresContext& aPresContext, if (!mSprings[count].collapsed) { // reflow if the child needs it or we are on a second pass - // if (mSprings[count].needsReflow || passes > 0) { - FlowChildAt(childFrame, aPresContext, aDesiredSize, aReflowState, aStatus, count, incrementalChild); - - // if its height greater than the max. Set the max to this height and set a flag - // saying we will need to do another pass. But keep going there - // may be another child that is bigger - if (mHorizontal) { - if (rect.height == NS_INTRINSICSIZE || aDesiredSize.height > rect.height) { - rect.height = aDesiredSize.height; - finished = PR_FALSE; - changedIndex = count; - for (int i=0; i < mSpringCount; i++) - resized[i] = PR_FALSE; - } - - // if we are wider than we anticipated then - // then this child can't get smaller then the size returned - // so set its minSize to be the desired and restretch. Then - // just start over because the springs are all messed up - // anyway. - if (aDesiredSize.width > mSprings[count].calculatedSize.width) { - mSprings[count].calculatedSize.width = aDesiredSize.width; - resized[count] = PR_TRUE; - - for (int i=0; i < mSpringCount; i++) - mSprings[i].sizeValid = resized[i]; + FlowChildAt(childFrame, aPresContext, aDesiredSize, aReflowState, aStatus, mSprings[count], redraw, reason); - finished = PR_FALSE; - changedIndex = count; - } - - - } else { - if (rect.width == NS_INTRINSICSIZE || aDesiredSize.width > rect.width) { - rect.width = aDesiredSize.width; - finished = PR_FALSE; - changedIndex = count; - for (int i=0; i < mSpringCount; i++) - resized[i] = PR_FALSE; - } - - - if (aDesiredSize.height > mSprings[count].calculatedSize.height) { - mSprings[count].calculatedSize.height = aDesiredSize.height; - - resized[count] = PR_TRUE; - - for (int i=0; i < mSpringCount; i++) - mSprings[i].sizeValid = resized[i]; - - LayoutChildrenInRect(rect); - finished = PR_FALSE; - changedIndex = count; - } + // if the child got bigger then adjust our rect and all the children. + ChildResized(aDesiredSize, rect, mSprings[count], resized, changedIndex, finished, count, nextReason); } - } + nsresult rv = childFrame->GetNextSibling(&childFrame); NS_ASSERTION(rv == NS_OK,"failed to get next child"); count++; + reason = nextReason; } // if we get over 10 passes something probably when wrong. @@ -489,9 +494,184 @@ nsBoxFrame::FlowChildren(nsIPresContext& aPresContext, } while (PR_FALSE == finished); + // redraw things if needed. + if (redraw) { +#if DEBUG_REDRAW + ListTag(stdout); + printf("is being redrawn\n"); +#endif + Invalidate(nsRect(0,0,mRect.width, mRect.height), PR_FALSE); + } + return NS_OK; } +void +nsBoxFrame::ChildResized(nsHTMLReflowMetrics& aDesiredSize, nsRect& aRect, nsCalculatedBoxInfo& aInfo, PRBool* aResized, nscoord& aChangedIndex, PRBool& aFinished, nscoord aIndex, nsString& aReason) +{ + if (mHorizontal) { + // if we are a horizontal box see if the child will fit inside us. + if ( aDesiredSize.height > aRect.height) { + // if we are a horizontal box and the the child it bigger than our height + + // ok if the height changed then we need to reflow everyone but us at the new height + // so we will set the changed index to be us. And signal that we need a new pass. + aRect.height = aDesiredSize.height; + + // remember we do not need to clear the resized list because changing the height of a horizontal box + // will not affect the width of any of its children because block flow left to right, top to bottom. Just trust me + // on this one. + aFinished = PR_FALSE; + aChangedIndex = aIndex; + + // relayout everything + InvalidateChildren(); + LayoutChildrenInRect(aRect); + aReason = "child's height got bigger"; + } else if (aDesiredSize.width > aInfo.calculatedSize.width) { + // if the child is wider than we anticipated. This can happend for children that we were not able to get a + // take on their min width. Like text, or tables. + + // because things flow from left to right top to bottom we know that + // if we get wider that we can set the min size. This will only work + // for width not height. Height must always be recalculated! + aInfo.minSize.width = aDesiredSize.width; + + // our width now becomes the new size + aInfo.calculatedSize.width = aDesiredSize.width; + + InvalidateChildren(); + + // our index resized + aResized[aIndex] = PR_TRUE; + + // if the width changed. mark our child as being resized + for (int i=0; i < mSpringCount; i++) + mSprings[i].sizeValid = aResized[i]; + + LayoutChildrenInRect(aRect); + aFinished = PR_FALSE; + aChangedIndex = aIndex; + aReason = "child's width got bigger"; + } + } else { + if ( aDesiredSize.width > aRect.width) { + // ok if the height changed then we need to reflow everyone but us at the new height + // so we will set the changed index to be us. And signal that we need a new pass. + aRect.width = aDesiredSize.width; + + // because things flow from left to right top to bottom we know that + // if we get wider that we can set the min size. This will only work + // for width not height. Height must always be recalculated! + aInfo.minSize.width = aDesiredSize.width; + + // if the width changed then clear out the resized list + // but only do this if we are vertical box. On a horizontal box increasing the height will not change the + // width of its children. + for (int i=0; i < mSpringCount; i++) + aResized[i] = PR_FALSE; + + aFinished = PR_FALSE; + aChangedIndex = aIndex; + + // relayout everything + InvalidateChildren(); + LayoutChildrenInRect(aRect); + aReason = "child's height got bigger"; + } else if (aDesiredSize.height > aInfo.calculatedSize.height) { + // our width now becomes the new size + aInfo.calculatedSize.height = aDesiredSize.height; + + InvalidateChildren(); + + // our index resized + aResized[aIndex] = PR_TRUE; + + // if the width changed. mark our child as being resized + for (int i=0; i < mSpringCount; i++) + mSprings[i].sizeValid = aResized[i]; + + LayoutChildrenInRect(aRect); + aFinished = PR_FALSE; + aChangedIndex = aIndex; + aReason = "child's width got bigger"; + } + } +} + + +/* +void +nsBoxFrame::ChildResized(nsHTMLReflowMetrics& aDesiredSize, nsRect& aRect, nsCalculatedBoxInfo& aInfo, PRBool[] aResized, nscoord& aChangedIndex, PRBool& aFinished, nscoord aIndex) +{ + // this code is designed to work in both dimensions. It is written as if we were only dealing + // with a horizontal box. But if we get a vertical box the values will be inverted. + // width becomes height and height becomes width. The purpose of this code is to correctly relayout + // if a child get larger than what we told it to layout as. This can happend a lot with text. Say + // we have a div and we layout it out in a vertical box with a width of 100px. The text must wrap. + // this will make the height of the div taller than expected. We would normally only expect it to + // by its prefered height of 1 line. So we must shuffle things. The idea is to have a list of + // resized children. If a child gets gets bigger a bit will be set in the resized array. This + // tells the layout system not to recalculate the size of that child when we relayout out. + + nscoord& desiredHeight = GET_HEIGHT(aDesiredSize); + nscoord& rectHeight = GET_HEIGHT(aRect); + nscoord& desiredWidth = GET_WIDTH(aDesiredSize); + nscoord& rectWidth = GET_WIDTH(aRect); + nscoord& calculatedWidth = GET_WIDTH(aInfo.calculatedSize); + + if (desiredHeight > rectHeight) { + // ok if the height changed then we need to reflow everyone but us at the new height + // so we will set the changed index to be us. And signal that we need a new pass. + rectHeight = desiredHeight; + + // because things flow from left to right top to bottom we know that + // if we get wider that we can set the min size. This will only work + // for width not height. Height must always be recalculated! + if (!mHorizontal) + aInfo.minSize.width = desiredHeight; + + aFinished = PR_FALSE; + aChangedIndex = aIndex; + + // if the height changed then clear out the resized list + // but only do this if we are horizontal box. In that case an increase in height + // can not affect + for (int i=0; i < mSprings; i++) + resized[i] = PR_FALSE; + + // relayout everything + InvalidateChildren(); + LayoutChildrenInRect(rect); + aReason = "child's height got bigger"; + } else if (desiredWidth > calculatedWidth) { + + // because things flow from left to right top to bottom we know that + // if we get wider that we can set the min size. This will only work + // for width not height. Height must always be recalculated! + if (mHorizontal) + aInfo.minSize.width = desiredWidth; + + // our width now becomes the new size + calculatedWidth = desiredWidth; + + InvalidateChildren(); + + // our index resized + resized[index] = PR_TRUE; + + // if the width changed. mark our child as being resized + for (int i=0; i < mSprings; i++) + mSprings[i].sizeValid = resized[i]; + + LayoutChildrenInRect(rect); + aFinished = PR_FALSE; + aChangedIndex = count; + aReason = "child's width got bigger"; + } +} +*/ + /* void CollapseChildren(nsIFrame* frame) { @@ -590,6 +770,7 @@ nsBoxFrame::PlaceChildren(nsRect& boxRect) return NS_OK; } + /** * Flow an individual child. Special args: * count: the spring that will be used to lay out the child @@ -603,14 +784,21 @@ nsBoxFrame::FlowChildAt(nsIFrame* childFrame, nsHTMLReflowMetrics& desiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus, - nscoord spring, - nsIFrame*& incrementalChild) + nsCalculatedBoxInfo& aInfo, + PRBool& aRedraw, + nsString& aReason) { -#if 0 -ListTag(stdout); printf(": reflowing "); -nsFrame::ListTag(stdout, childFrame); -printf("\n"); -#endif + + nsReflowReason reason = aReflowState.reason; + PRBool shouldReflow = PR_TRUE; + + // if the reason is incremental and the child is not marked as incremental. Then relow the child + // as a resize instead. + if (aInfo.isIncremental) + reason = eReflowReason_Incremental; + else if (reason == eReflowReason_Incremental) + reason = eReflowReason_Resize; + // subtract out the childs margin and border const nsStyleSpacing* spacing; nsresult rv = childFrame->GetStyleData(eStyleStruct_Spacing, @@ -618,34 +806,31 @@ printf("\n"); nsMargin margin; spacing->GetMargin(margin); - nsMargin border; - spacing->GetBorderPadding(border); - nsMargin total = margin + border; - const nsStylePosition* position; - rv = childFrame->GetStyleData(eStyleStruct_Position, - (const nsStyleStruct*&) position); - - nsReflowReason reason = aReflowState.reason; - PRBool shouldReflow = PR_TRUE; - - // so if we are incremental and have already reflowed the incremental child or there is an incremental child - // and its not this one make sure we change the reason to resize. - if (reason == eReflowReason_Incremental && (nsnull == incrementalChild || incrementalChild != childFrame)) - reason = eReflowReason_Resize; + // get the current size of the child + nsRect currentRect(0,0,0,0); + childFrame->GetRect(currentRect); // if we don't need a reflow then // lets see if we are already that size. Yes? then don't even reflow. We are done. - if (!mSprings[spring].needsReflow) { - nsRect currentSize; - childFrame->GetRect(currentSize); + if (!aInfo.needsReflow && aInfo.calculatedSize.width != NS_INTRINSICSIZE && aInfo.calculatedSize.height != NS_INTRINSICSIZE) { - if (currentSize.width > 0 && currentSize.height > 0) - { - desiredSize.width = currentSize.width; - desiredSize.height = currentSize.height; + // if the new calculated size has a 0 width or a 0 height + if ((currentRect.width == 0 || currentRect.height == 0) && (aInfo.calculatedSize.width == 0 || aInfo.calculatedSize.height == 0)) { + shouldReflow = PR_FALSE; + desiredSize.width = aInfo.calculatedSize.width - (margin.left + margin.right); + desiredSize.height = aInfo.calculatedSize.height - (margin.top + margin.bottom); + childFrame->SizeTo(desiredSize.width, desiredSize.height); + } else { + desiredSize.width = currentRect.width; + desiredSize.height = currentRect.height; - if (currentSize.width == mSprings[spring].calculatedSize.width && currentSize.height == mSprings[spring].calculatedSize.height) + // remove the margin. The rect of our child does not include it but our calculated size does. + nscoord calcWidth = aInfo.calculatedSize.width - (margin.left + margin.right); + nscoord calcHeight = aInfo.calculatedSize.height - (margin.top + margin.bottom); + + // don't reflow if we are already the right size + if (currentRect.width == calcWidth && currentRect.height == calcHeight) shouldReflow = PR_FALSE; } } @@ -653,68 +838,56 @@ printf("\n"); // ok now reflow the child into the springs calculated space if (shouldReflow) { + nsMargin border; + spacing->GetBorderPadding(border); + nsMargin total = margin + border; + + const nsStylePosition* position; + rv = childFrame->GetStyleData(eStyleStruct_Position, + (const nsStyleStruct*&) position); + desiredSize.width = 0; desiredSize.height = 0; + nsSize size(aInfo.calculatedSize.width, aInfo.calculatedSize.height); + + // only subrtact margin + if (size.height != NS_INTRINSICSIZE) + size.height -= (margin.top + margin.bottom); + + + if (size.width != NS_INTRINSICSIZE) + size.width -= (margin.left + margin.right); + // create a reflow state to tell our child to flow at the given size. - nsHTMLReflowState reflowState(aPresContext, aReflowState, childFrame, nsSize(NS_INTRINSICSIZE, NS_INTRINSICSIZE)); + nsHTMLReflowState reflowState(aPresContext, aReflowState, childFrame, nsSize(size.width, NS_INTRINSICSIZE)); reflowState.reason = reason; + if (size.height != NS_INTRINSICSIZE) + size.height -= (border.top + border.bottom); + + if (size.width != NS_INTRINSICSIZE) + size.width -= (border.left + border.right); + // tell the child what size they should be - reflowState.mComputedWidth = mSprings[spring].calculatedSize.width; - reflowState.mComputedHeight = mSprings[spring].calculatedSize.height; + reflowState.mComputedWidth = size.width; + reflowState.mComputedHeight = size.height; - // only subrtact margin and border. - if (reflowState.mComputedWidth != NS_INTRINSICSIZE) - reflowState.mComputedWidth -= (total.left + total.right); - - if (reflowState.mComputedHeight != NS_INTRINSICSIZE) - reflowState.mComputedHeight -= (total.top + total.bottom); - - // HTML frames do not implement nsIBox so unless they set both their width and height we do not know - // what there preferred size is. We can assume a preferred width or height of 0 when flexable but when - // not flexible we are in trouble. Why? Well if the child is fixed we really want its intrinsic size and - // the only way to get it is to flow with NS_INTRINSIC. So lets do that if we have to. - if (mSprings[spring].flex == CONSTANT) { - if (mHorizontal) { - if (mSprings[spring].prefWidthIntrinsic) - reflowState.mComputedWidth = NS_INTRINSICSIZE; - } else { - if (mSprings[spring].prefHeightIntrinsic) - reflowState.mComputedHeight = NS_INTRINSICSIZE; - } - } - - // HTML block don't seem to return the actually size they layed themselves - // out in if they did not fit. So if the height is 0 indicating no one set it them. Get this - // fixed in blocks themselves. - if (mHorizontal) { - // if we could not get the height of the child because it did not implement nsIBox and - // it did not provide a height via css and we are trying to lay it out with a height of 0 - if (mSprings[spring].prefHeightIntrinsic && reflowState.mComputedHeight != NS_INTRINSICSIZE) { - nscoord oldHeight = mSprings[spring].calculatedSize.height; - mSprings[spring].calculatedSize.height = NS_INTRINSICSIZE; - FlowChildAt(childFrame, aPresContext, desiredSize, aReflowState, aStatus, spring, incrementalChild); - - mSprings[spring].calculatedSize.height = oldHeight; - - // remember that when we get the size back it has its margin and borderpadding - // added to it! So we must remove it before we make the comparison - desiredSize.width -= (total.left + total.right); - desiredSize.height -= (total.top + total.bottom); - - // see if things are ok - if (reflowState.mComputedHeight < desiredSize.height) - reflowState.mComputedHeight = desiredSize.height; - - } - - } - - nsSize* oldMaxElementSize = desiredSize.maxElementSize; - nsSize maxElementSize(NS_INTRINSICSIZE, NS_INTRINSICSIZE); - desiredSize.maxElementSize = &maxElementSize; + // nsSize maxElementSize(0, 0); + // desiredSize.maxElementSize = &maxElementSize; +#if DEBUG_REFLOW + ListTag(stdout); + if (reason == eReflowReason_Incremental && aInfo.isIncremental) + printf(": INCREMENTALLY reflowing "); + else + printf(": reflowing "); + + nsFrame::ListTag(stdout, childFrame); + char ch[100]; + aReason.ToCString(ch,100); + printf("because (%s)\n", ch); +#endif // do the flow nsIHTMLReflow* htmlReflow; @@ -723,28 +896,73 @@ printf("\n"); htmlReflow->WillReflow(aPresContext); htmlReflow->Reflow(aPresContext, desiredSize, reflowState, aStatus); + NS_ASSERTION(NS_FRAME_IS_COMPLETE(aStatus), "bad status"); - if (maxElementSize.width != NS_INTRINSICSIZE && maxElementSize.width > desiredSize.width) - desiredSize.width = maxElementSize.width; + nsFrameState kidState; + childFrame->GetFrameState(&kidState); + + // printf("width: %d, height: %d\n", desiredSize.mCombinedArea.width, desiredSize.mCombinedArea.height); + + if (kidState & NS_FRAME_OUTSIDE_CHILDREN) { + desiredSize.width = desiredSize.mCombinedArea.width; + desiredSize.height = desiredSize.mCombinedArea.height; + } + + +// if (maxElementSize.width > desiredSize.width) + // desiredSize.width = maxElementSize.width; + + PRBool changedSize = PR_FALSE; + + if (currentRect.width != desiredSize.width || currentRect.height != desiredSize.height) + changedSize = PR_TRUE; + + // if the child got bigger then make sure the new size in our min max range + if (changedSize) { + + // redraw if we changed size. + aRedraw = PR_TRUE; + + if (aInfo.maxSize.width != NS_INTRINSICSIZE && desiredSize.width > aInfo.maxSize.width - (margin.left + margin.right)) + desiredSize.width = aInfo.maxSize.width - (margin.left + margin.right); + + // if the child was bigger than anticipated and there was a min size set thennn + if (aInfo.calculatedSize.width != NS_INTRINSICSIZE && position->mMinWidth.GetUnit() == eStyleUnit_Coord) { + nscoord min = position->mMinWidth.GetCoordValue(); + if (min != 0) + desiredSize.width = aInfo.calculatedSize.width - (margin.left + margin.right); + } + + if (aInfo.maxSize.height != NS_INTRINSICSIZE && desiredSize.height > aInfo.maxSize.height - (margin.top + margin.bottom)) + desiredSize.height = aInfo.maxSize.height - (margin.top + margin.bottom); + + // if a min size was set we will always get the desired height + if (aInfo.calculatedSize.height != NS_INTRINSICSIZE && position->mMinHeight.GetUnit() == eStyleUnit_Coord) { + nscoord min = position->mMinHeight.GetCoordValue(); + if (min != 0) + desiredSize.height = aInfo.calculatedSize.height - (margin.top + margin.bottom); + } + + } // set the rect - childFrame->SetRect(nsRect(0,0,desiredSize.width, desiredSize.height)); + childFrame->SizeTo(desiredSize.width, desiredSize.height); // Stub out desiredSize.maxElementSize so that when go out of // scope, nothing bad happens! - desiredSize.maxElementSize = oldMaxElementSize; + desiredSize.maxElementSize = nsnull; // clear out the incremental child, so that we don't flow it incrementally again - if (reason == eReflowReason_Incremental && incrementalChild == childFrame) - incrementalChild = nsnull; + if (reason == eReflowReason_Incremental && aInfo.isIncremental) + aInfo.isIncremental = PR_FALSE; } // add the margin back in. The child should add its border automatically desiredSize.height += (margin.top + margin.bottom); desiredSize.width += (margin.left + margin.right); - mSprings[spring].needsReflow = PR_FALSE; + aInfo.needsReflow = PR_FALSE; return NS_OK; } @@ -764,7 +982,6 @@ nsBoxFrame::BoundsCheck(const nsBoxInfo& aBoxInfo, nsRect& aRect) if (aRect.width == NS_INTRINSICSIZE ) aRect.width = aBoxInfo.prefSize.width; - // make sure the available size is no bigger than the max size if (aRect.height > aBoxInfo.maxSize.height) aRect.height = aBoxInfo.maxSize.height; @@ -1045,14 +1262,6 @@ nsBoxFrame::GetBoxInfo(nsIPresContext& aPresContext, const nsHTMLReflowState& aR nscoord count = 0; nsIFrame* childFrame = mFrames.FirstChild(); - /* - // if we have any children assume we are intrinsic unless a child is not - if (childFrame != nsnull) { - aSize.prefHeightIntrinsic = PR_TRUE; - aSize.prefWidthIntrinsic = PR_TRUE; - } - */ - while (nsnull != childFrame) { // if a child needs recalculation then ask it for its size. Otherwise @@ -1088,30 +1297,28 @@ nsBoxFrame::GetBoxInfo(nsIPresContext& aPresContext, const nsHTMLReflowState& aR nsSize m(margin.left+margin.right,margin.top+margin.bottom); mSprings[count].minSize += m; mSprings[count].prefSize += m; + if (mSprings[count].maxSize.width != NS_INTRINSICSIZE) + mSprings[count].maxSize.width += m.width; + + if (mSprings[count].maxSize.height != NS_INTRINSICSIZE) + mSprings[count].maxSize.height += m.height; spacing->GetBorderPadding(margin); nsSize b(margin.left+margin.right,margin.top+margin.bottom); mSprings[count].minSize += b; mSprings[count].prefSize += b; + if (mSprings[count].maxSize.width != NS_INTRINSICSIZE) + mSprings[count].maxSize.width += b.width; + + if (mSprings[count].maxSize.height != NS_INTRINSICSIZE) + mSprings[count].maxSize.height += b.height; } // ok we don't need to calc this guy again mSprings[count].needsRecalc = PR_FALSE; } - /* - // if a size is not intrinsic then our size is not intrinsic. - if (!mSprings[count].prefWidthIntrinsic) - aSize.prefWidthIntrinsic = PR_FALSE; - - if (!mSprings[count].prefHeightIntrinsic) - aSize.prefHeightIntrinsic = PR_FALSE; - */ - - // now that we know our child's min, max, pref sizes figure OUR size from them. - AddSize(mSprings[count].minSize, aSize.minSize, PR_FALSE); - AddSize(mSprings[count].maxSize, aSize.maxSize, PR_TRUE); - AddSize(mSprings[count].prefSize, aSize.prefSize, PR_FALSE); + AddChildSize(aSize, mSprings[count]); rv = childFrame->GetNextSibling(&childFrame); NS_ASSERTION(rv == NS_OK,"failed to get next child"); @@ -1135,9 +1342,20 @@ nsBoxFrame::GetBoxInfo(nsIPresContext& aPresContext, const nsHTMLReflowState& aR return rv; } +void +nsBoxFrame::AddChildSize(nsBoxInfo& aInfo, nsBoxInfo& aChildInfo) +{ + // now that we know our child's min, max, pref sizes figure OUR size from them. + AddSize(aChildInfo.minSize, aInfo.minSize, PR_FALSE); + AddSize(aChildInfo.maxSize, aInfo.maxSize, PR_TRUE); + AddSize(aChildInfo.prefSize, aInfo.prefSize, PR_FALSE); +} + /** - * Called with a reflow command. This will dirty all boxes who need to be reflowed. - * return the last child that is not a box. Part of nsIBox interface. + * Boxes work differently that regular HTML elements. Each box knows if it needs to be reflowed or not + * So when a box gets an incremental reflow. It runs down all the children and marks them for reflow. If it + * Reaches a child that is not a box then it marks that child as incremental so when it is flowed next it + * will be flowed incrementally. */ NS_IMETHODIMP nsBoxFrame::Dirty(const nsHTMLReflowState& aReflowState, nsIFrame*& incrementalChild) @@ -1163,7 +1381,14 @@ nsBoxFrame::Dirty(const nsHTMLReflowState& aReflowState, nsIFrame*& incrementalC ibox->Dirty(aReflowState, incrementalChild); else incrementalChild = frame; + + // if we found a leaf. Then mark it as being incremental. So when we + // flow it we will flow it incrementally + if (incrementalChild == childFrame) + mSprings[count].isIncremental = PR_TRUE; + break; + } rv = childFrame->GetNextSibling(&childFrame); @@ -1177,6 +1402,41 @@ nsBoxFrame::Dirty(const nsHTMLReflowState& aReflowState, nsIFrame*& incrementalC return rv; } +NS_IMETHODIMP +nsBoxFrame :: Paint ( nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer) +{ + const nsStyleDisplay* disp = (const nsStyleDisplay*) + mStyleContext->GetStyleData(eStyleStruct_Display); + + // if we aren't visible then we are done. + if (!disp->mVisible) + return NS_OK; + + // if we are visible then tell our superclass to paint + nsresult r = nsHTMLContainerFrame::Paint(aPresContext, aRenderingContext, aDirtyRect, + aWhichLayer); + + // paint the draw area + /* +#if DEBUG_REDRAW + if (NS_BLOCK_DOCUMENT_ROOT & mFlags) { + PRBool result = PR_FALSE; + nsRect rect(0,0,0,0); + aRenderingContext.GetClipRect(rect, result); + if (result) { + aRenderingContext.SetColor(NS_RGB(255,0,0)); + aRenderingContext.DrawRect(rect); + } + } +#endif +*/ + return r; +} + + NS_IMETHODIMP nsBoxFrame::QueryInterface(REFNSIID aIID, void** aInstancePtr) { if (NULL == aInstancePtr) { @@ -1218,6 +1478,19 @@ nsCalculatedBoxInfo::nsCalculatedBoxInfo() clear(); } +nsCalculatedBoxInfo::nsCalculatedBoxInfo(const nsBoxInfo& aInfo):nsBoxInfo(aInfo) +{ + needsReflow = PR_TRUE; + needsRecalc = PR_TRUE; + collapsed = PR_FALSE; + + calculatedSize.width = 0; + calculatedSize.height = 0; + + sizeValid = PR_FALSE; + isIncremental = PR_FALSE; +} + void nsCalculatedBoxInfo::clear() { diff --git a/layout/xul/base/src/nsBoxFrame.h b/layout/xul/base/src/nsBoxFrame.h index a117eefdc503..236b32f6439c 100644 --- a/layout/xul/base/src/nsBoxFrame.h +++ b/layout/xul/base/src/nsBoxFrame.h @@ -42,8 +42,10 @@ public: PRBool needsReflow; PRBool needsRecalc; PRBool collapsed; + PRBool isIncremental; nsCalculatedBoxInfo(); + nsCalculatedBoxInfo(const nsBoxInfo& aInfo); virtual void clear(); }; @@ -56,7 +58,7 @@ public: // nsIBox methods NS_IMETHOD GetBoxInfo(nsIPresContext& aPresContext, const nsHTMLReflowState& aReflowState, nsBoxInfo& aSize); - NS_IMETHOD Dirty(const nsHTMLReflowState& aReflowState, nsIFrame*& incrementalChild); + NS_IMETHOD Dirty(const nsHTMLReflowState& aReflowState, nsIFrame*& aIncrementalChild); NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr); @@ -73,6 +75,10 @@ public: nsIAtom* aAttribute, PRInt32 aHint); + NS_IMETHOD Paint ( nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer); NS_IMETHOD Reflow(nsIPresContext& aPresContext, nsHTMLReflowMetrics& aDesiredSize, @@ -113,47 +119,37 @@ protected: nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus, - nsRect& availableSize, - nsIFrame*& incrementalChild); + nsRect& availableSize); virtual nsresult FlowChildAt(nsIFrame* frame, nsIPresContext& aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus, - nscoord spring, - nsIFrame*& incrementalChild); + nsCalculatedBoxInfo& aInfo, + PRBool& needsRedraw, + nsString& aReason); virtual nsresult PlaceChildren(nsRect& boxRect); - - + virtual void ChildResized(nsHTMLReflowMetrics& aDesiredSize, nsRect& aRect, nsCalculatedBoxInfo& aInfo, PRBool* aResized, nscoord& aChangedIndex, PRBool& aFinished, nscoord aIndex, nsString& aReason); + virtual void LayoutChildrenInRect(nsRect& size); + virtual void AddChildSize(nsBoxInfo& aInfo, nsBoxInfo& aChildInfo); virtual void BoundsCheck(const nsBoxInfo& aBoxInfo, nsRect& aRect); - - /* - virtual void GetDesiredSize(nsIPresContext* aPresContext, - const nsHTMLReflowState& aReflowState, - nsHTMLReflowMetrics& aDesiredSize); - */ + virtual void InvalidateChildren(); + virtual void AddSize(const nsSize& a, nsSize& b, PRBool largest); virtual PRIntn GetSkipSides() const { return 0; } - virtual void GetInset(nsMargin& margin); - - virtual void LayoutChildrenInRect(nsRect& size); - - virtual void InvalidateChildren(); - - virtual void AddSize(const nsSize& a, nsSize& b, PRBool largest); - + virtual void GetInset(nsMargin& margin); PRBool mHorizontal; + nsCalculatedBoxInfo mSprings[100]; + nscoord mSpringCount; private: // XXX for the moment we can only handle 100 children. // Should use a dynamic array. - nsCalculatedBoxInfo mSprings[100]; - nscoord mSpringCount; nsCOMPtr mSpaceManager; // We own this [OWNER]. PRUint32 mFlags; diff --git a/layout/xul/base/src/nsDeckFrame.cpp b/layout/xul/base/src/nsDeckFrame.cpp index b35d1b804380..7b6d3f7930f2 100644 --- a/layout/xul/base/src/nsDeckFrame.cpp +++ b/layout/xul/base/src/nsDeckFrame.cpp @@ -39,12 +39,8 @@ #include "nsIPresShell.h" #include "nsStyleChangeList.h" #include "nsCSSRendering.h" +#include "nsIViewManager.h" -/* -void -ApplyRenderingChangeToTree(nsIPresContext* aPresContext, - nsIFrame* aFrame); -*/ nsresult NS_NewDeckFrame ( nsIFrame** aNewFrame ) @@ -62,13 +58,6 @@ NS_NewDeckFrame ( nsIFrame** aNewFrame ) } // NS_NewDeckFrame -/* -nsDeckFrame::nsDeckFrame() -{ -} -*/ - - NS_IMETHODIMP nsDeckFrame::Init(nsIPresContext& aPresContext, nsIContent* aContent, @@ -77,8 +66,7 @@ nsDeckFrame::Init(nsIPresContext& aPresContext, nsIFrame* aPrevInFlow) { // Get the element's tag - nsresult rv = nsHTMLContainerFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow); - mSelectedChanged = PR_TRUE; + nsresult rv = nsBoxFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow); return rv; } @@ -89,46 +77,13 @@ nsDeckFrame::AttributeChanged(nsIPresContext* aPresContext, nsIAtom* aAttribute, PRInt32 aHint) { - nsresult rv = nsHTMLContainerFrame::AttributeChanged(aPresContext, aChild, + nsresult rv = nsBoxFrame::AttributeChanged(aPresContext, aChild, aAttribute, aHint); // if the index changed hide the old element and make the now element visible if (aAttribute == nsHTMLAtoms::value) { - /* - nsCOMPtr show ( getter_AddRefs(NS_NewAtom(":-moz-deck-showing")) ); - nsCOMPtr hide ( getter_AddRefs(NS_NewAtom(":-moz-deck-hidden")) ); - - if (nsnull != mSelected) - ForceResolveToPseudoElement(*aPresContext,mSelected, hide); - */ - - /* - // reflow - nsCOMPtr shell; - aPresContext->GetShell(getter_AddRefs(shell)); - - nsCOMPtr reflowCmd; - nsresult rv = NS_NewHTMLReflowCommand(getter_AddRefs(reflowCmd), this, - nsIReflowCommand::StyleChanged); - if (NS_SUCCEEDED(rv)) - shell->AppendReflowCommand(reflowCmd); - */ - - /* - if (nsnull != frame) - { - mSelected = frame; - ForceResolveToPseudoElement(*aPresContext,mSelected, show); - } -*/ - // ApplyRenderingChangeToTree(aPresContext, this); - - /* - nsRect rect(0, 0, mRect.width, mRect.height); - Invalidate(rect, PR_TRUE); - */ } @@ -206,209 +161,6 @@ nsDeckFrame::Paint(nsIPresContext& aPresContext, } -NS_IMETHODIMP -nsDeckFrame::Reflow(nsIPresContext& aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus) -{ - - // if there is incremental we need to tell all nsIBoxes below to blow away the - // cached values for the children in the reflow list - nsIFrame* incrementalChild = nsnull; - if ( aReflowState.reason == eReflowReason_Incremental ) { - Dirty(aReflowState,incrementalChild); - } - - // get our available size - nsSize availableSize(aReflowState.mComputedWidth,aReflowState.mComputedHeight); - - // if the width or height are intrinsic then lay us our children out at our preferred size - if (aReflowState.mComputedWidth == NS_INTRINSICSIZE || aReflowState.mComputedHeight == NS_INTRINSICSIZE) - { - // get our size - nsBoxInfo ourSize; - GetBoxInfo(aPresContext, aReflowState, ourSize); - - if (aReflowState.mComputedWidth == NS_INTRINSICSIZE) - availableSize.width = ourSize.prefSize.width; - - if (aReflowState.mComputedHeight == NS_INTRINSICSIZE) - availableSize.height = ourSize.prefSize.height; - } - - aDesiredSize.width = 0; - aDesiredSize.height = 0; - - // iterate though each child - PRBool finished = PR_FALSE; - nsIFrame* changedChild = nsnull; - int passes = 0; - - while(!finished) - { - finished = PR_TRUE; - nscoord count = 0; - nsIFrame* childFrame = mFrames.FirstChild(); - while (nsnull != childFrame) - { - // if we hit the child that cause us to do a second pass - // then break. - if (changedChild == childFrame) - break; - - FlowChildAt(childFrame, aPresContext, aDesiredSize, aReflowState, aStatus, availableSize, incrementalChild); - - // if the area returned is greater than our size - if (aDesiredSize.height > availableSize.height || aDesiredSize.width > availableSize.width) - { - // note the child that got bigger - changedChild = childFrame; - - // set our size to be the new size - if (aDesiredSize.width > availableSize.width) - availableSize.width = aDesiredSize.width; - - if (aDesiredSize.height > availableSize.height) - availableSize.height = aDesiredSize.height; - - // indicate we need to start another pass - finished = PR_FALSE; - } - - // get the next child - nsresult rv = childFrame->GetNextSibling(&childFrame); - count++; - } - - // if we get over 10 passes something probably when wrong. - passes++; - if (passes > 5) - NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, - ("DeckFrame reflow bug")); - - NS_ASSERTION(passes <= 10,"DeckFrame: Error infinte loop too many passes"); - } - - // return the largest dimension - aDesiredSize.width = availableSize.width; - aDesiredSize.height = availableSize.height; - - // add in our border - const nsMargin& borderPadding = aReflowState.mComputedBorderPadding; - - aDesiredSize.width += borderPadding.left + borderPadding.right; - aDesiredSize.height += borderPadding.top + borderPadding.bottom; - aDesiredSize.ascent = aDesiredSize.height; - aDesiredSize.descent = 0; - - return NS_OK; -} - -nsresult -nsDeckFrame::FlowChildAt(nsIFrame* childFrame, - nsIPresContext& aPresContext, - nsHTMLReflowMetrics& desiredSize, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus, - const nsSize& size, - nsIFrame*& incrementalChild) -{ - - // subtract out the childs margin and border - const nsStyleSpacing* spacing; - nsresult rv = childFrame->GetStyleData(eStyleStruct_Spacing, - (const nsStyleStruct*&) spacing); - - nsMargin margin; - spacing->GetMargin(margin); - nsMargin border; - spacing->GetBorderPadding(border); - nsMargin total = margin + border; - - const nsStylePosition* position; - rv = childFrame->GetStyleData(eStyleStruct_Position, - (const nsStyleStruct*&) position); - - nsReflowReason reason = aReflowState.reason; - PRBool shouldReflow = PR_TRUE; - - // so if we are incremental and have already reflowed the incremental child or there is an incremental child - // and its not this one make sure we change the reason to resize. - if (reason == eReflowReason_Incremental && (nsnull == incrementalChild || incrementalChild != childFrame)) { - reason = eReflowReason_Resize; - nsRect currentSize; - childFrame->GetRect(currentSize); - - if (currentSize.width > 0 && currentSize.height > 0) - { - desiredSize.width = currentSize.width; - desiredSize.height = currentSize.height; - - if (currentSize.width == size.width && currentSize.height == size.height) - shouldReflow = PR_FALSE; - } - } - - // ok now reflow the child into the springs calculated space - if (shouldReflow) { - - desiredSize.width = 0; - desiredSize.height = 0; - - // create a reflow state to tell our child to flow at the given size. - nsHTMLReflowState reflowState(aPresContext, aReflowState, childFrame, nsSize(NS_INTRINSICSIZE, NS_INTRINSICSIZE)); - reflowState.reason = reason; - - reflowState.mComputedWidth = size.width; - reflowState.mComputedHeight = size.height; - - // only subrtact margin and border. - reflowState.mComputedWidth -= (total.left + total.right); - reflowState.mComputedHeight -= (total.top + total.bottom); - - nsSize maxElementSize(NS_INTRINSICSIZE, NS_INTRINSICSIZE); - - // do the flow - nsIHTMLReflow* htmlReflow; - - rv = childFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow); - NS_ASSERTION(rv == NS_OK,"failed to get htmlReflow interface."); - - htmlReflow->WillReflow(aPresContext); - htmlReflow->Reflow(aPresContext, desiredSize, reflowState, aStatus); - NS_ASSERTION(NS_FRAME_IS_COMPLETE(aStatus), "bad status"); - - // set the rect - childFrame->SetRect(nsRect(aReflowState.mComputedBorderPadding.left,aReflowState.mComputedBorderPadding.top,desiredSize.width, desiredSize.height)); - } - - // add the margin back in. The child should add its border automatically - desiredSize.height += (margin.top + margin.bottom); - desiredSize.width += (margin.left + margin.right); - - return NS_OK; -} - - -/* -NS_IMETHODIMP -nsDeckFrame::HandleEvent(nsIPresContext& aPresContext, - nsGUIEvent* aEvent, - nsEventStatus& aEventStatus) -{ - - // send the event to the selected frame - nsIFrame* selectedFrame = GetSelectedFrame(); - - // if no selected frame we handle the event - if (nsnull == selectedFrame) - return nsHTMLContainerFrame::HandleEvent(aPresContext, aEvent, aEventStatus); - - return selectedFrame->HandleEvent(aPresContext, aEvent, aEventStatus); -} -*/ - NS_IMETHODIMP nsDeckFrame::GetFrameForPoint(const nsPoint& aPoint, nsIFrame** aFrame) { @@ -435,48 +187,13 @@ NS_IMETHODIMP nsDeckFrame::GetFrameForPoint(const nsPoint& aPoint, return NS_OK; } -/* -NS_IMETHODIMP -nsDeckFrame::SetInitialChildList(nsIPresContext& aPresContext, - nsIAtom* aListName, - nsIFrame* aChildList) -{ - nsresult r = nsHTMLContainerFrame::SetInitialChildList(aPresContext, aListName, aChildList); - - nsIFrame* frame = GetSelectedFrame(); - - nsIFrame* childFrame = mFrames.FirstChild(); - while (nsnull != childFrame) - { - // if we hit the child that cause us to do a second pass - // then break. - if (childFrame != frame) - { - mSelected = frame; - AddStyle(mSelected, gVisibleStyle); - mSelected->ReResolveStyleContext(&aPresContext, mStyleContext, - NS_STYLE_HINT_REFLOW, - nsnull, nsnull); - } else { - RemoveStyle(mSelected, gHiddenStyle); - mSelected->ReResolveStyleContext(&aPresContext, mStyleContext, - NS_STYLE_HINT_REFLOW, - nsnull, nsnull); - - } - } - - return r; -} -*/ - NS_IMETHODIMP nsDeckFrame::SetInitialChildList(nsIPresContext& aPresContext, nsIAtom* aListName, nsIFrame* aChildList) { - nsresult r = nsHTMLContainerFrame::SetInitialChildList(aPresContext, aListName, aChildList); + nsresult r = nsBoxFrame::SetInitialChildList(aPresContext, aListName, aChildList); // now that all the children are added. ReResolve our children // so we hide everything that is hidden in the deck @@ -487,258 +204,30 @@ nsDeckFrame::SetInitialChildList(nsIPresContext& aPresContext, } -NS_IMETHODIMP -nsDeckFrame::RemoveFrame(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aOldFrame) + +void +nsDeckFrame::AddChildSize(nsBoxInfo& aInfo, nsBoxInfo& aChildInfo) { - // remove the child frame - nsresult rv = nsHTMLContainerFrame::RemoveFrame(aPresContext, aPresShell, aListName, aOldFrame); - mFrames.DestroyFrame(aPresContext, aOldFrame); - return rv; -} + // largest preferred size + if (aInfo.prefSize.width > aChildInfo.prefSize.width) + aChildInfo.prefSize.width = aInfo.prefSize.width; -NS_IMETHODIMP -nsDeckFrame::InsertFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList) -{ - mFrames.InsertFrames(nsnull, aPrevFrame, aFrameList); - return nsHTMLContainerFrame::InsertFrames(aPresContext, aPresShell, aListName, aPrevFrame, aFrameList); -} + if (aInfo.prefSize.height > aChildInfo.prefSize.height) + aChildInfo.prefSize.height = aInfo.prefSize.height; -NS_IMETHODIMP -nsDeckFrame::AppendFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aFrameList) -{ - mFrames.AppendFrames(nsnull, aFrameList); - return nsHTMLContainerFrame::AppendFrames(aPresContext, aPresShell, aListName, aFrameList); -} + // largest min size + if (aInfo.minSize.width > aChildInfo.minSize.width) + aChildInfo.minSize.width = aInfo.minSize.width; -/** - * Goes though each child asking for its size to determine our size. Returns our deck size minus our border. - * This method is defined in nsIBox interface. - */ -NS_IMETHODIMP -nsDeckFrame::GetBoxInfo(nsIPresContext& aPresContext, const nsHTMLReflowState& aReflowState, nsBoxInfo& aSize) -{ - nsresult rv; + if (aInfo.minSize.height > aChildInfo.minSize.height) + aChildInfo.minSize.height = aInfo.minSize.height; - aSize.clear(); + // smallest max size + if (aInfo.maxSize.width < aChildInfo.maxSize.width) + aChildInfo.maxSize.width = aInfo.maxSize.width; - // run through all the children and get there min, max, and preferred sizes - // return us the size of the deck - nscoord count = 0; - nsIFrame* childFrame = mFrames.FirstChild(); - - while (nsnull != childFrame) - { - nsBoxInfo info; - // get the size of the child. This is the min, max, preferred, and spring constant - // it does not include its border. - rv = GetChildBoxInfo(aPresContext, aReflowState, childFrame, info); - NS_ASSERTION(rv == NS_OK,"failed to get child box info"); - if (NS_FAILED(rv)) - return rv; - - // add in the child's margin and border/padding if there is one. - const nsStyleSpacing* spacing; - nsresult rv = childFrame->GetStyleData(eStyleStruct_Spacing, - (const nsStyleStruct*&) spacing); - - NS_ASSERTION(rv == NS_OK,"failed to get spacing info"); - if (NS_FAILED(rv)) - return rv; - - nsMargin margin; - spacing->GetMargin(margin); - nsSize m(margin.left+margin.right,margin.top+margin.bottom); - info.minSize += m; - info.prefSize += m; - - spacing->GetBorderPadding(margin); - nsSize b(margin.left+margin.right,margin.top+margin.bottom); - info.minSize += b; - info.prefSize += b; - - // largest preferred size - if (info.prefSize.width > aSize.prefSize.width) - aSize.prefSize.width = info.prefSize.width; - - if (info.prefSize.height > aSize.prefSize.height) - aSize.prefSize.height = info.prefSize.height; - - // largest min size - if (info.minSize.width > aSize.minSize.width) - aSize.minSize.width = info.minSize.width; - - if (info.minSize.height > aSize.minSize.height) - aSize.minSize.height = info.minSize.height; - - // smallest max size - if (info.maxSize.width < aSize.maxSize.width) - aSize.maxSize.width = info.maxSize.width; - - if (info.maxSize.height < aSize.maxSize.height) - aSize.maxSize.height = info.maxSize.height; - - rv = childFrame->GetNextSibling(&childFrame); - NS_ASSERTION(rv == NS_OK,"failed to get next child"); - if (NS_FAILED(rv)) - return rv; - - count++; - } - - return rv; -} - -nsresult -nsDeckFrame::GetChildBoxInfo(nsIPresContext& aPresContext, const nsHTMLReflowState& aReflowState, nsIFrame* aFrame, nsBoxInfo& aSize) -{ - aSize.clear(); - - // see if the frame implements IBox interface - nsCOMPtr ibox = do_QueryInterface(aFrame); - - // if it does ask it for its BoxSize and we are done - if (ibox) { - ibox->GetBoxInfo(aPresContext, aReflowState, aSize); - // add in the border, padding, width, min, max - GetRedefinedMinPrefMax(aFrame, aSize); - return NS_OK; - } else { - GetRedefinedMinPrefMax(aFrame, aSize); - } - - - - // set the pref width and height to be intrinsic. - aSize.prefWidthIntrinsic = PR_TRUE; - aSize.prefHeightIntrinsic = PR_TRUE;; - - return NS_OK; -} - -/** - * Looks at the given frame and sees if its redefined preferred, min, or max sizes - * if so it used those instead. Currently it gets its values from css - */ -void -nsDeckFrame::GetRedefinedMinPrefMax(nsIFrame* aFrame, nsBoxInfo& aSize) -{ - // add in the css min, max, pref - const nsStylePosition* position; - nsresult rv = aFrame->GetStyleData(eStyleStruct_Position, - (const nsStyleStruct*&) position); - - // see if the width or height was specifically set - if (position->mWidth.GetUnit() == eStyleUnit_Coord) { - aSize.prefSize.width = position->mWidth.GetCoordValue(); - aSize.prefWidthIntrinsic = PR_FALSE; - } - - if (position->mHeight.GetUnit() == eStyleUnit_Coord) { - aSize.prefSize.height = position->mHeight.GetCoordValue(); - aSize.prefHeightIntrinsic = PR_FALSE; - } - - // same for min size. Unfortunately min size is always set to 0. So for now - // we will assume 0 means not set. - if (position->mMinWidth.GetUnit() == eStyleUnit_Coord) { - nscoord min = position->mMinWidth.GetCoordValue(); - if (min != 0) - aSize.minSize.width = min; - } - - if (position->mMinHeight.GetUnit() == eStyleUnit_Coord) { - nscoord min = position->mMinHeight.GetCoordValue(); - if (min != 0) - aSize.minSize.height = min; - } - - // and max - if (position->mMaxWidth.GetUnit() == eStyleUnit_Coord) { - nscoord max = position->mMaxWidth.GetCoordValue(); - aSize.maxSize.width = max; - } - - if (position->mMaxHeight.GetUnit() == eStyleUnit_Coord) { - nscoord max = position->mMaxHeight.GetCoordValue(); - aSize.maxSize.height = max; - } -} - -/** - * Called with a reflow command. This will dirty all boxes who need to be reflowed. - * return the last child that is not a box. Part of nsIBox interface. - */ -NS_IMETHODIMP -nsDeckFrame::Dirty(const nsHTMLReflowState& aReflowState, nsIFrame*& incrementalChild) -{ - incrementalChild = nsnull; - nsresult rv = NS_OK; - - // Dirty any children that need it. - nsIFrame* frame; - aReflowState.reflowCommand->GetNext(frame); - nscoord count = 0; - nsIFrame* childFrame = mFrames.FirstChild(); - while (nsnull != childFrame) - { - if (childFrame == frame) { - // clear the spring so it is recalculated on the flow - nsCOMPtr ibox = do_QueryInterface(childFrame); - if (ibox) - ibox->Dirty(aReflowState, incrementalChild); - else - incrementalChild = frame; - break; - } - - rv = childFrame->GetNextSibling(&childFrame); - NS_ASSERTION(rv == NS_OK,"failed to get next child"); - if (NS_FAILED(rv)) - return rv; - - count++; - } - - return rv; -} - -NS_IMETHODIMP nsDeckFrame::QueryInterface(REFNSIID aIID, void** aInstancePtr) -{ - if (NULL == aInstancePtr) { - return NS_ERROR_NULL_POINTER; - } - - *aInstancePtr = NULL; - - if (aIID.Equals(kIBoxIID)) { - *aInstancePtr = (void*)(nsIBox*) this; - NS_ADDREF_THIS(); - return NS_OK; - } - - return nsHTMLContainerFrame::QueryInterface(aIID, aInstancePtr); -} - -NS_IMETHODIMP_(nsrefcnt) -nsDeckFrame::AddRef(void) -{ - return NS_OK; -} - -NS_IMETHODIMP_(nsrefcnt) -nsDeckFrame::Release(void) -{ - return NS_OK; + if (aInfo.maxSize.height < aChildInfo.maxSize.height) + aChildInfo.maxSize.height = aInfo.maxSize.height; } NS_IMETHODIMP @@ -830,3 +319,75 @@ nsDeckFrame :: ReResolveStyleContext ( nsIPresContext* aPresContext, nsIStyleCon } // ReResolveStyleContext + +nsresult +nsDeckFrame::PlaceChildren(nsRect& boxRect) +{ + // ------- set the childs positions --------- + nscoord x = boxRect.x; + nscoord y = boxRect.y; + + nsIFrame* childFrame = mFrames.FirstChild(); + nscoord count = 0; + while (nsnull != childFrame) + { + nsresult rv; + + // make collapsed children not show up + if (mSprings[count].collapsed) { + + childFrame->SetRect(nsRect(0,0,0,0)); + + // make the view really small as well + nsIView* view = nsnull; + childFrame->GetView(&view); + + if (view) { + nsCOMPtr vm; + view->GetViewManager(*getter_AddRefs(vm)); + vm->ResizeView(view, 0,0); + } + + } else { + nsRect rect; + childFrame->MoveTo(rect.x, rect.y); + } + + rv = childFrame->GetNextSibling(&childFrame); + NS_ASSERTION(rv == NS_OK,"failed to get next child"); + count++; + } + + return NS_OK; +} + +void +nsDeckFrame::ChildResized(nsHTMLReflowMetrics& aDesiredSize, nsRect& aRect, nsCalculatedBoxInfo& aInfo, PRBool* aResized, nscoord& aChangedIndex, PRBool& aFinished, nscoord aIndex, nsString& aReason) +{ + if (aDesiredSize.width > aRect.width) { + aRect.width = aDesiredSize.width; + InvalidateChildren(); + LayoutChildrenInRect(aRect); + aReason = "child's width got bigger"; + aChangedIndex = aIndex; + aFinished = PR_FALSE; + } else if (aDesiredSize.height > aRect.height) { + aRect.height = aDesiredSize.height; + InvalidateChildren(); + LayoutChildrenInRect(aRect); + aReason = "child's height got bigger"; + aChangedIndex = aIndex; + aFinished = PR_FALSE; + } +} + +void +nsDeckFrame::LayoutChildrenInRect(nsRect& size) +{ + for (int i=0; i shell; aPresContext->GetShell(getter_AddRefs(shell)); @@ -704,6 +704,10 @@ nsTitledButtonFrame::Reflow(nsIPresContext& aPresContext, { mNeedsLayout = PR_TRUE; nsresult result = nsLeafFrame::Reflow(aPresContext, aMetrics, aReflowState, aStatus); + + // redraw us on a reflow + Invalidate(nsRect(0,0,mRect.width, mRect.height), PR_FALSE); + return result; }