Fixed boxes to only invalidate and redraw what has changed.

Made min and max sizes work
Made linux not suck!
This commit is contained in:
scc%netscape.com 1999-07-23 00:11:21 +00:00
Родитель 5f74f88c68
Коммит b1c73fa7c7
7 изменённых файлов: 633 добавлений и 812 удалений

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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()
{

Просмотреть файл

@ -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<nsISpaceManager> mSpaceManager; // We own this [OWNER].
PRUint32 mFlags;

Просмотреть файл

@ -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<nsIAtom> show ( getter_AddRefs(NS_NewAtom(":-moz-deck-showing")) );
nsCOMPtr<nsIAtom> hide ( getter_AddRefs(NS_NewAtom(":-moz-deck-hidden")) );
if (nsnull != mSelected)
ForceResolveToPseudoElement(*aPresContext,mSelected, hide);
*/
/*
// reflow
nsCOMPtr<nsIPresShell> shell;
aPresContext->GetShell(getter_AddRefs(shell));
nsCOMPtr<nsIReflowCommand> 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<nsIBox> 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<nsIBox> 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<nsIViewManager> 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<mSpringCount; i++) {
mSprings[i].calculatedSize.width = size.width;
mSprings[i].calculatedSize.height = size.height;
mSprings[i].sizeValid = PR_TRUE;
}
}

Просмотреть файл

@ -28,22 +28,15 @@
#ifndef nsDeckFrame_h___
#define nsDeckFrame_h___
#include "nsHTMLContainerFrame.h"
#include "nsIBox.h"
#include "nsBoxFrame.h"
class nsDeckFrame : public nsHTMLContainerFrame, public nsIBox
class nsDeckFrame : public nsBoxFrame
{
public:
friend nsresult NS_NewDeckFrame(nsIFrame** aNewFrame);
NS_IMETHOD GetBoxInfo(nsIPresContext& aPresContext, const nsHTMLReflowState& aReflowState, nsBoxInfo& aSize);
NS_IMETHOD Dirty(const nsHTMLReflowState& aReflowState, nsIFrame*& incrementalChild);
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
NS_IMETHOD_(nsrefcnt) AddRef(void);
NS_IMETHOD_(nsrefcnt) Release(void);
NS_IMETHOD ReResolveStyleContext ( nsIPresContext* aPresContext,
nsIStyleContext* aParentContext,
@ -63,42 +56,17 @@ public:
nsIAtom* aAttribute,
PRInt32 aHint);
NS_IMETHOD Reflow(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus);
NS_IMETHOD Paint(nsIPresContext& aPresContext,
nsIRenderingContext& aRenderingContext,
const nsRect& aDirtyRect,
nsFramePaintLayer aWhichLayer);
NS_IMETHOD AppendFrames(nsIPresContext& aPresContext,
nsIPresShell& aPresShell,
nsIAtom* aListName,
nsIFrame* aFrameList);
NS_IMETHOD InsertFrames(nsIPresContext& aPresContext,
nsIPresShell& aPresShell,
nsIAtom* aListName,
nsIFrame* aPrevFrame,
nsIFrame* aFrameList);
NS_IMETHOD RemoveFrame(nsIPresContext& aPresContext,
nsIPresShell& aPresShell,
nsIAtom* aListName,
nsIFrame* aOldFrame);
NS_IMETHOD SetInitialChildList(nsIPresContext& aPresContext,
nsIAtom* aListName,
nsIFrame* aChildList);
/*
NS_IMETHOD HandleEvent(nsIPresContext& aPresContext,
nsGUIEvent* aEvent,
nsEventStatus& aEventStatus);
*/
NS_IMETHOD GetFrameForPoint(const nsPoint& aPoint,
nsIFrame** aFrame);
@ -107,21 +75,16 @@ public:
protected:
virtual nsIFrame* GetSelectedFrame();
virtual nsresult GetChildBoxInfo(nsIPresContext& aPresContext, const nsHTMLReflowState& aReflowState, nsIFrame* aFrame, nsBoxInfo& aSize);
virtual void GetRedefinedMinPrefMax(nsIFrame* aFrame, nsBoxInfo& aSize);
virtual nsresult FlowChildAt(nsIFrame* frame,
nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus,
const nsSize& size,
nsIFrame*& incrementalChild);
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);
private:
nsIFrame* mSelected;
PRBool mSelectedChanged;
}; // class nsDeckFrame

Просмотреть файл

@ -151,7 +151,7 @@ nsTitledButtonFrame::AttributeChanged(nsIPresContext* aPresContext,
mNeedsLayout = PR_TRUE;
UpdateAttributes(*aPresContext);
#if 0
#if 1 // added back in because boxes now handle only redraw what is reflowed.
// reflow
nsCOMPtr<nsIPresShell> 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;
}