зеркало из https://github.com/mozilla/pjs.git
Implemented incremental reflow for boxes.
This commit is contained in:
Родитель
ccfa189100
Коммит
2fc7284055
|
@ -104,6 +104,118 @@ nsBoxFrame::Paint(nsIPresContext& aPresContext,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBoxFrame::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);
|
||||
|
||||
|
||||
// start off with an empty size
|
||||
desiredSize.width = 0;
|
||||
desiredSize.height = 0;
|
||||
|
||||
nsReflowReason reason = aReflowState.reason;
|
||||
PRBool shouldReflow = PR_TRUE;
|
||||
|
||||
if (nsnull != incrementalChild && incrementalChild != childFrame) {
|
||||
// if we are flowing because of incremental and this is not
|
||||
// the child then see if the size is already what we want.
|
||||
// if it is then keep it and don't bother reflowing.
|
||||
nsRect currentSize;
|
||||
childFrame->GetRect(currentSize);
|
||||
|
||||
desiredSize.width = currentSize.width;
|
||||
desiredSize.height = currentSize.height;
|
||||
|
||||
// XXX ok there needs to be a little more work here. The child
|
||||
// could move another child out of the way causing a reflow of
|
||||
// a different child. In this case we need to reflow the affected
|
||||
// area. So yes we need to reflow. Make sure we change the reason
|
||||
// so we don't lose the incremental reflow path.
|
||||
|
||||
PRBool wsame = (mHorizontal && NS_INTRINSICSIZE == size.width);
|
||||
PRBool hsame = (!mHorizontal && NS_INTRINSICSIZE == size.height);
|
||||
|
||||
if ((wsame || currentSize.width == size.width) && (hsame || currentSize.height == size.height))
|
||||
shouldReflow = PR_FALSE;
|
||||
else
|
||||
reason = eReflowReason_StyleChange;
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (shouldReflow) {
|
||||
// flow the child
|
||||
const nsStylePosition* pos;
|
||||
childFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)pos);
|
||||
|
||||
nsStyleCoord* w = (nsStyleCoord*)&pos->mWidth;
|
||||
nsStyleCoord wcopy(*w);
|
||||
*w = nsStyleCoord();
|
||||
w->SetPercentValue(1);
|
||||
|
||||
nsStyleCoord* h = (nsStyleCoord*)&pos->mHeight;
|
||||
nsStyleCoord hcopy(*h);
|
||||
*h = nsStyleCoord();
|
||||
h->SetPercentValue(1);
|
||||
|
||||
nsHTMLReflowState reflowState(aPresContext, aReflowState, childFrame, size);
|
||||
reflowState.reason = reason;
|
||||
|
||||
reflowState.computedWidth = size.width;
|
||||
reflowState.computedHeight = size.height;
|
||||
|
||||
// only subrtact margin and border if the size is not intrinsic
|
||||
if (NS_INTRINSICSIZE != reflowState.computedWidth)
|
||||
reflowState.computedWidth -= (total.left + total.right);
|
||||
|
||||
|
||||
if (NS_INTRINSICSIZE != reflowState.computedHeight)
|
||||
reflowState.computedHeight -= (total.top + total.bottom);
|
||||
|
||||
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");
|
||||
|
||||
*w = wcopy;
|
||||
*h = hcopy;
|
||||
|
||||
// set the rect
|
||||
childFrame->SetRect(nsRect(0,0,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;
|
||||
}
|
||||
|
||||
class nsBoxDataSpring {
|
||||
public:
|
||||
nscoord preferredSize;
|
||||
|
@ -129,89 +241,6 @@ public:
|
|||
|
||||
};
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBoxFrame::FlowChildAt(nsIFrame* childFrame,
|
||||
nsIPresContext& aPresContext,
|
||||
nsHTMLReflowMetrics& desiredSize,
|
||||
const nsHTMLReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus,
|
||||
const nsSize& size)
|
||||
{
|
||||
// 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);
|
||||
|
||||
|
||||
// start off with an empty size
|
||||
desiredSize.width = 0;
|
||||
desiredSize.height = 0;
|
||||
|
||||
// flow the child
|
||||
const nsStylePosition* pos;
|
||||
childFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)pos);
|
||||
|
||||
nsStyleCoord* w = (nsStyleCoord*)&pos->mWidth;
|
||||
nsStyleCoord wcopy(*w);
|
||||
*w = nsStyleCoord();
|
||||
w->SetPercentValue(1);
|
||||
|
||||
nsStyleCoord* h = (nsStyleCoord*)&pos->mHeight;
|
||||
nsStyleCoord hcopy(*h);
|
||||
*h = nsStyleCoord();
|
||||
h->SetPercentValue(1);
|
||||
|
||||
nsHTMLReflowState reflowState(aPresContext, aReflowState, childFrame, size);
|
||||
|
||||
reflowState.computedWidth = size.width;
|
||||
reflowState.computedHeight = size.height;
|
||||
|
||||
// only subrtact margin and border if the size is not intrinsic
|
||||
if (NS_INTRINSICSIZE != reflowState.computedWidth)
|
||||
{
|
||||
reflowState.computedWidth -= (total.left + total.right);
|
||||
}
|
||||
|
||||
|
||||
if (NS_INTRINSICSIZE != reflowState.computedHeight)
|
||||
{
|
||||
reflowState.computedHeight -= (total.top + total.bottom);
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
*w = wcopy;
|
||||
*h = hcopy;
|
||||
|
||||
// set the rect
|
||||
childFrame->SetRect(nsRect(0,0,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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ok what we want to do here is get all the children, figure out
|
||||
* their flexibility, preferred, min, max sizes and then stretch or
|
||||
|
@ -262,27 +291,18 @@ nsBoxFrame::Reflow(nsIPresContext& aPresContext,
|
|||
if (NS_INTRINSICSIZE != availableSize.height)
|
||||
availableSize.height -= (inset.top + inset.bottom);
|
||||
|
||||
|
||||
// Until I can handle incremental reflow correctly (or at all), I need to at
|
||||
// least make sure that I don't be a bad citizen. This will certainly betray my
|
||||
// complete lack of understanding of the reflow code, but I think I need to
|
||||
// make sure that I advance to the next reflow command to make everything down
|
||||
// the line matches up.
|
||||
// handle incremental reflow
|
||||
// get the child and only reflow it
|
||||
nsIFrame* incrementalChild = nsnull;
|
||||
if ( aReflowState.reason == eReflowReason_Incremental ) {
|
||||
nsIFrame* target;
|
||||
aReflowState.reflowCommand->GetTarget(target);
|
||||
if (this != target) {
|
||||
// ignore the next reflow command and proceed as normal...
|
||||
nsIFrame* ignore;
|
||||
aReflowState.reflowCommand->GetNext(ignore);
|
||||
}
|
||||
aReflowState.reflowCommand->GetNext(incrementalChild);
|
||||
}
|
||||
|
||||
// ------ first pass build springs -------
|
||||
|
||||
nsBoxDataSpring springs[100];
|
||||
nscoord totalCount = 0;
|
||||
|
||||
// go though each child
|
||||
// go though each child
|
||||
nsHTMLReflowMetrics desiredSize = aDesiredSize;
|
||||
nsSize totalMinSize = availableSize;
|
||||
nsSize minSize(0,0);
|
||||
|
@ -293,119 +313,121 @@ nsBoxFrame::Reflow(nsIPresContext& aPresContext,
|
|||
nsIFrame* childFrame = mFrames.FirstChild();
|
||||
while (nsnull != childFrame)
|
||||
{
|
||||
// create a spring
|
||||
springs[count].init();
|
||||
// create a spring
|
||||
springs[count].init();
|
||||
|
||||
desiredSize.width = 0;
|
||||
desiredSize.height = 0;
|
||||
desiredSize.width = 0;
|
||||
desiredSize.height = 0;
|
||||
|
||||
// get the preferred size
|
||||
const nsStylePosition* position;
|
||||
nsresult rv = childFrame->GetStyleData(eStyleStruct_Position,
|
||||
(const nsStyleStruct*&) position);
|
||||
// get the preferred size
|
||||
const nsStylePosition* position;
|
||||
nsresult rv = childFrame->GetStyleData(eStyleStruct_Position,
|
||||
(const nsStyleStruct*&) position);
|
||||
|
||||
nsStyleUnit wunit = position->mWidth.GetUnit();
|
||||
nsStyleUnit hunit = position->mHeight.GetUnit();
|
||||
nsStyleUnit wunit = position->mWidth.GetUnit();
|
||||
nsStyleUnit hunit = position->mHeight.GetUnit();
|
||||
|
||||
// if we don't know the exact width or height then
|
||||
// get the instrinsic size for our preferred.
|
||||
// get the min and max size
|
||||
const nsStyleCoord* minWidth;
|
||||
const nsStyleCoord* minHeight;
|
||||
const nsStyleCoord* maxWidth;
|
||||
const nsStyleCoord* maxHeight;
|
||||
// if we don't know the exact width or height then
|
||||
// get the instrinsic size for our preferred.
|
||||
// get the min and max size
|
||||
const nsStyleCoord* minWidth;
|
||||
const nsStyleCoord* minHeight;
|
||||
const nsStyleCoord* maxWidth;
|
||||
const nsStyleCoord* maxHeight;
|
||||
|
||||
minWidth = &position->mMinWidth;
|
||||
minHeight = &position->mMinHeight;
|
||||
maxWidth = &position->mMaxWidth;
|
||||
maxHeight = &position->mMaxHeight;
|
||||
minWidth = &position->mMinWidth;
|
||||
minHeight = &position->mMinHeight;
|
||||
maxWidth = &position->mMaxWidth;
|
||||
maxHeight = &position->mMaxHeight;
|
||||
|
||||
if (minWidth->GetUnit() == eStyleUnit_Coord)
|
||||
minSize.width = minWidth->GetCoordValue();
|
||||
if (minWidth->GetUnit() == eStyleUnit_Coord)
|
||||
minSize.width = minWidth->GetCoordValue();
|
||||
|
||||
if (minHeight->GetUnit() == eStyleUnit_Coord)
|
||||
minSize.height = minHeight->GetCoordValue();
|
||||
if (minHeight->GetUnit() == eStyleUnit_Coord)
|
||||
minSize.height = minHeight->GetCoordValue();
|
||||
|
||||
if (maxWidth->GetUnit() == eStyleUnit_Coord)
|
||||
maxSize.width = maxWidth->GetCoordValue();
|
||||
if (maxWidth->GetUnit() == eStyleUnit_Coord)
|
||||
maxSize.width = maxWidth->GetCoordValue();
|
||||
|
||||
if (maxHeight->GetUnit() == eStyleUnit_Coord)
|
||||
maxSize.height = maxHeight->GetCoordValue();
|
||||
if (maxHeight->GetUnit() == eStyleUnit_Coord)
|
||||
maxSize.height = maxHeight->GetCoordValue();
|
||||
|
||||
if (mHorizontal) {
|
||||
springs[count].minSize = minSize.width;
|
||||
springs[count].maxSize = maxSize.width;
|
||||
} else {
|
||||
springs[count].minSize = minSize.height;
|
||||
springs[count].maxSize = maxSize.height;
|
||||
}
|
||||
if (mHorizontal) {
|
||||
springs[count].minSize = minSize.width;
|
||||
springs[count].maxSize = maxSize.width;
|
||||
} else {
|
||||
springs[count].minSize = minSize.height;
|
||||
springs[count].maxSize = maxSize.height;
|
||||
}
|
||||
|
||||
// get the greatest min size
|
||||
if (minSize.height > totalMinSize.height)
|
||||
totalMinSize.height = minSize.height;
|
||||
// get the greatest min size
|
||||
if (minSize.height > totalMinSize.height)
|
||||
totalMinSize.height = minSize.height;
|
||||
|
||||
if (minSize.width > totalMinSize.width)
|
||||
totalMinSize.width = minSize.width;
|
||||
if (minSize.width > totalMinSize.width)
|
||||
totalMinSize.width = minSize.width;
|
||||
|
||||
nsSize flexSize(totalMinSize);
|
||||
if (mHorizontal)
|
||||
flexSize.width = NS_INTRINSICSIZE;
|
||||
else
|
||||
flexSize.height = NS_INTRINSICSIZE;
|
||||
nsSize flexSize(totalMinSize);
|
||||
if (mHorizontal)
|
||||
flexSize.width = NS_INTRINSICSIZE;
|
||||
else
|
||||
flexSize.height = NS_INTRINSICSIZE;
|
||||
|
||||
// get the content
|
||||
nsCOMPtr<nsIContent> content;
|
||||
childFrame->GetContent(getter_AddRefs(content));
|
||||
// get the content
|
||||
nsCOMPtr<nsIContent> content;
|
||||
childFrame->GetContent(getter_AddRefs(content));
|
||||
|
||||
PRInt32 error;
|
||||
nsString value;
|
||||
PRInt32 error;
|
||||
nsString value;
|
||||
|
||||
// get the spring constant
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE == content->GetAttribute(kNameSpaceID_None, nsXULAtoms::flex, value))
|
||||
{
|
||||
value.Trim("%");
|
||||
float percent = value.ToFloat(&error);
|
||||
springs[count].springConstant = percent;
|
||||
}
|
||||
// get the spring constant
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE == content->GetAttribute(kNameSpaceID_None, nsXULAtoms::flex, value))
|
||||
{
|
||||
value.Trim("%");
|
||||
float percent = value.ToFloat(&error);
|
||||
springs[count].springConstant = percent;
|
||||
}
|
||||
|
||||
if (mHorizontal) {
|
||||
if (wunit == eStyleUnit_Percent)
|
||||
springs[count].springConstant = position->mWidth.GetPercentValue();
|
||||
} else {
|
||||
if (hunit == eStyleUnit_Percent)
|
||||
springs[count].springConstant = position->mHeight.GetPercentValue();
|
||||
}
|
||||
if (mHorizontal) {
|
||||
if (wunit == eStyleUnit_Percent)
|
||||
springs[count].springConstant = position->mWidth.GetPercentValue();
|
||||
} else {
|
||||
if (hunit == eStyleUnit_Percent)
|
||||
springs[count].springConstant = position->mHeight.GetPercentValue();
|
||||
}
|
||||
|
||||
// only flow if fixed and width or height was not set
|
||||
if (springs[count].springConstant == 0.0 && (wunit != eStyleUnit_Coord || hunit != eStyleUnit_Coord)) {
|
||||
springs[count].wasFlowed = PR_TRUE;
|
||||
FlowChildAt(childFrame,aPresContext, desiredSize, aReflowState, aStatus, flexSize);
|
||||
}
|
||||
// only flow if fixed and width or height was not set
|
||||
if (springs[count].springConstant == 0.0 && (wunit != eStyleUnit_Coord || hunit != eStyleUnit_Coord))
|
||||
{
|
||||
springs[count].wasFlowed = PR_TRUE;
|
||||
|
||||
FlowChildAt(childFrame,aPresContext, desiredSize, aReflowState, aStatus, flexSize, incrementalChild);
|
||||
}
|
||||
|
||||
if (desiredSize.height > maxDesiredSize.height)
|
||||
maxDesiredSize.height = desiredSize.height;
|
||||
if (desiredSize.height > maxDesiredSize.height)
|
||||
maxDesiredSize.height = desiredSize.height;
|
||||
|
||||
if (desiredSize.width > maxDesiredSize.width)
|
||||
maxDesiredSize.width = desiredSize.width;
|
||||
if (desiredSize.width > maxDesiredSize.width)
|
||||
maxDesiredSize.width = desiredSize.width;
|
||||
|
||||
if (wunit == eStyleUnit_Coord)
|
||||
desiredSize.width = position->mWidth.GetCoordValue();
|
||||
if (wunit == eStyleUnit_Coord)
|
||||
desiredSize.width = position->mWidth.GetCoordValue();
|
||||
|
||||
if (hunit == eStyleUnit_Coord)
|
||||
desiredSize.height = position->mHeight.GetCoordValue();
|
||||
if (hunit == eStyleUnit_Coord)
|
||||
desiredSize.height = position->mHeight.GetCoordValue();
|
||||
|
||||
if (NS_INTRINSICSIZE == desiredSize.width)
|
||||
desiredSize.width = 0;
|
||||
if (NS_INTRINSICSIZE == desiredSize.width)
|
||||
desiredSize.width = 0;
|
||||
|
||||
if (NS_INTRINSICSIZE == desiredSize.height)
|
||||
desiredSize.height = 0;
|
||||
if (NS_INTRINSICSIZE == desiredSize.height)
|
||||
desiredSize.height = 0;
|
||||
|
||||
if (mHorizontal)
|
||||
springs[count].preferredSize = desiredSize.width;
|
||||
else
|
||||
springs[count].preferredSize = desiredSize.height;
|
||||
if (mHorizontal)
|
||||
springs[count].preferredSize = desiredSize.width;
|
||||
else
|
||||
springs[count].preferredSize = desiredSize.height;
|
||||
|
||||
|
||||
|
||||
|
||||
rv = childFrame->GetNextSibling(&childFrame);
|
||||
NS_ASSERTION(rv == NS_OK,"failed to get next child");
|
||||
|
@ -425,7 +447,7 @@ nsBoxFrame::Reflow(nsIPresContext& aPresContext,
|
|||
}
|
||||
|
||||
// total number of children
|
||||
nscoord totalCount = count;
|
||||
totalCount = count;
|
||||
|
||||
// ------ second pass flow -------
|
||||
|
||||
|
@ -463,10 +485,8 @@ nsBoxFrame::Reflow(nsIPresContext& aPresContext,
|
|||
childFrame->GetRect(r);
|
||||
|
||||
if (springs[count].wasFlowed == PR_FALSE || (size.width != r.width || size.height!=r.height)) {
|
||||
|
||||
// flow child
|
||||
FlowChildAt(childFrame,aPresContext, desiredSize, aReflowState, aStatus, size);
|
||||
|
||||
|
||||
FlowChildAt(childFrame,aPresContext, desiredSize, aReflowState, aStatus, size, 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
|
||||
|
|
|
@ -41,7 +41,8 @@ public:
|
|||
nsHTMLReflowMetrics& aDesiredSize,
|
||||
const nsHTMLReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus,
|
||||
const nsSize& size);
|
||||
const nsSize& size,
|
||||
nsIFrame* incrementalChild);
|
||||
|
||||
|
||||
NS_IMETHOD Init(nsIPresContext& aPresContext,
|
||||
|
@ -99,8 +100,8 @@ protected:
|
|||
private:
|
||||
|
||||
|
||||
|
||||
}; // class nsBoxFrame
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче