Bug 300030: Move intrinsic width computation out of nsIFrame::Reflow and into its own methods on nsIFrame. Replace reflow reasons, types, and commands with dirty bits/notifications. Thanks to bzbarsky for almost all of the HTML form controls (mozilla/layout/forms) changes, and many others for help testing and patching. For detailed commit logs, see REFLOW_YYYYMMDD_BRANCH, where YYYYMMDD is one of 20061031, 20060830, 20060603, 20060302, 20060119, 20051011, 20050804, 20050429, 20050315, 20050111, and 20041213.

git-svn-id: svn://10.0.0.236/trunk@216738 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
dbaron%dbaron.org
2006-12-08 05:38:33 +00:00
parent 1a1de382fe
commit 1ca9f3f372
201 changed files with 8730 additions and 18257 deletions

View File

@@ -61,7 +61,6 @@
#include "nsFormControlFrame.h"
#include "nsFrameManager.h"
#include "nsINameSpaceManager.h"
#include "nsReflowPath.h"
#include "nsIServiceManager.h"
#include "nsIDOMHTMLButtonElement.h"
#include "nsIDOMHTMLInputElement.h"
@@ -81,9 +80,6 @@ NS_NewHTMLButtonControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
nsHTMLButtonControlFrame::nsHTMLButtonControlFrame(nsStyleContext* aContext)
: nsHTMLContainerFrame(aContext)
{
mCacheSize.width = -1;
mCacheSize.height = -1;
mCachedMaxElementWidth = -1;
}
nsHTMLButtonControlFrame::~nsHTMLButtonControlFrame()
@@ -104,7 +100,9 @@ nsHTMLButtonControlFrame::Init(
nsIFrame* aPrevInFlow)
{
nsresult rv = nsHTMLContainerFrame::Init(aContent, aParent, aPrevInFlow);
mRenderer.SetFrame(this, GetPresContext());
if (NS_SUCCEEDED(rv)) {
mRenderer.SetFrame(this, GetPresContext());
}
return rv;
}
@@ -248,6 +246,51 @@ nsHTMLButtonControlFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
return DisplaySelectionOverlay(aBuilder, aLists);
}
nscoord
nsHTMLButtonControlFrame::GetMinWidth(nsIRenderingContext* aRenderingContext)
{
return DoGetMinWidth(aRenderingContext, PR_TRUE);
}
nscoord
nsHTMLButtonControlFrame::DoGetMinWidth(nsIRenderingContext* aRenderingContext,
PRBool aZeroIfWidthSpecified)
{
nscoord result;
DISPLAY_MIN_WIDTH(this, result);
// Note: to fix the button equivalent of bug 40596 while still working
// correctly in general, we want to return our actual min width as our min
// width if our style width is auto. Otherwise, we're ok with shrinking as
// small as needed.
if (!aZeroIfWidthSpecified ||
GetStylePosition()->mWidth.GetUnit() == eStyleUnit_Auto) {
nsIFrame* kid = mFrames.FirstChild();
result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
kid,
nsLayoutUtils::MIN_WIDTH);
result += mRenderer.GetAddedButtonBorderAndPadding().LeftRight();
} else {
result = 0;
}
return result;
}
nscoord
nsHTMLButtonControlFrame::GetPrefWidth(nsIRenderingContext* aRenderingContext)
{
nscoord result;
DISPLAY_PREF_WIDTH(this, result);
nsIFrame* kid = mFrames.FirstChild();
result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
kid,
nsLayoutUtils::PREF_WIDTH);
result += mRenderer.GetAddedButtonBorderAndPadding().LeftRight();
return result;
}
NS_IMETHODIMP
nsHTMLButtonControlFrame::Reflow(nsPresContext* aPresContext,
@@ -255,120 +298,62 @@ nsHTMLButtonControlFrame::Reflow(nsPresContext* aPresContext,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus)
{
DO_GLOBAL_REFLOW_COUNT("nsHTMLButtonControlFrame", aReflowState.reason);
DO_GLOBAL_REFLOW_COUNT("nsHTMLButtonControlFrame");
DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
if (eReflowReason_Initial == aReflowState.reason) {
NS_PRECONDITION(aReflowState.mComputedWidth != NS_INTRINSICSIZE,
"Should have real computed width by now");
if (mState & NS_FRAME_FIRST_REFLOW) {
nsFormControlFrame::RegUnRegAccessKey(NS_STATIC_CAST(nsIFrame*, this), PR_TRUE);
}
#if 0
nsresult skiprv = nsFormControlFrame::SkipResizeReflow(mCacheSize, mCachedMaxElementWidth, aPresContext,
aDesiredSize, aReflowState, aStatus);
if (NS_SUCCEEDED(skiprv)) {
return skiprv;
}
#endif
// Reflow the child
nsIFrame* firstKid = mFrames.FirstChild();
nsSize availSize(aReflowState.mComputedWidth, NS_INTRINSICSIZE);
// Indent the child inside us by the focus border. We must do this separate from the
// regular border.
// XXXbz Eventually we may want to check-and-bail if
// !aReflowState.ShouldReflowAllKids() &&
// !(firstKid->GetStateBits() &
// (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)).
// We'd need to cache our ascent for that, of course.
nsMargin focusPadding = mRenderer.GetAddedButtonBorderAndPadding();
if (NS_INTRINSICSIZE != availSize.width) {
availSize.width -= focusPadding.left + focusPadding.right;
availSize.width = PR_MAX(availSize.width,0);
}
if (NS_AUTOHEIGHT != availSize.height) {
availSize.height -= focusPadding.top + focusPadding.bottom;
availSize.height = PR_MAX(availSize.height,0);
}
// XXX Proper handling of incremental reflow...
nsReflowReason reason = aReflowState.reason;
if (eReflowReason_Incremental == reason) {
// See if it's targeted at us
nsHTMLReflowCommand *command = aReflowState.path->mReflowCommand;
if (command) {
// I'm not sure what exactly this Invalidate is for
Invalidate(nsRect(0,0,mRect.width,mRect.height), PR_FALSE);
nsReflowType reflowType;
command->GetType(reflowType);
if (eReflowType_StyleChanged == reflowType) {
reason = eReflowReason_StyleChange;
}
else {
reason = eReflowReason_Resize;
}
}
}
// Reflow the contents of the button a first time.
// Reflow the contents of the button.
ReflowButtonContents(aPresContext, aDesiredSize, aReflowState, firstKid,
availSize, reason, focusPadding, aStatus);
focusPadding, aStatus);
// If we just performed the first pass of a shrink-wrap reflow (which will have
// found the requested size of the children, but not placed them), perform
// the second pass of a shrink-wrap reflow (which places the children
// within this parent button which has now shrink-wrapped around them).
if (availSize.width == NS_SHRINKWRAPWIDTH) {
nsSize newAvailSize(aDesiredSize.width, NS_INTRINSICSIZE);
ReflowButtonContents(aPresContext, aDesiredSize, aReflowState, firstKid,
newAvailSize, eReflowReason_Resize, focusPadding, aStatus);
}
// If computed use the computed values.
if (aReflowState.mComputedWidth != NS_INTRINSICSIZE)
aDesiredSize.width = aReflowState.mComputedWidth;
else
aDesiredSize.width += focusPadding.left + focusPadding.right;
aDesiredSize.width = aReflowState.mComputedWidth;
// If computed use the computed value.
if (aReflowState.mComputedHeight != NS_INTRINSICSIZE)
aDesiredSize.height = aReflowState.mComputedHeight;
else
aDesiredSize.height += focusPadding.top + focusPadding.bottom;
aDesiredSize.height += focusPadding.TopBottom();
aDesiredSize.width += aReflowState.mComputedBorderPadding.LeftRight();
aDesiredSize.height += aReflowState.mComputedBorderPadding.TopBottom();
// Make sure we obey min/max-height. Note that we do this after adjusting
// for borderpadding, since buttons have border-box sizing...
aDesiredSize.width += aReflowState.mComputedBorderPadding.left + aReflowState.mComputedBorderPadding.right;
aDesiredSize.height += aReflowState.mComputedBorderPadding.top + aReflowState.mComputedBorderPadding.bottom;
// XXXbz unless someone overrides that, of course! We should really consider
// exposing nsHTMLReflowState::AdjustComputed* or something.
aDesiredSize.height = NS_CSS_MINMAX(aDesiredSize.height,
aReflowState.mComputedMinHeight,
aReflowState.mComputedMaxHeight);
if (aDesiredSize.mComputeMEW) {
aDesiredSize.SetMEWToActualWidth(aReflowState.mStylePosition->mWidth.GetUnit());
}
// Make sure we obey min/max-width and min/max-height
if (aDesiredSize.width > aReflowState.mComputedMaxWidth) {
aDesiredSize.width = aReflowState.mComputedMaxWidth;
}
if (aDesiredSize.width < aReflowState.mComputedMinWidth) {
aDesiredSize.width = aReflowState.mComputedMinWidth;
}
if (aDesiredSize.height > aReflowState.mComputedMaxHeight) {
aDesiredSize.height = aReflowState.mComputedMaxHeight;
}
if (aDesiredSize.height < aReflowState.mComputedMinHeight) {
aDesiredSize.height = aReflowState.mComputedMinHeight;
}
aDesiredSize.ascent += aReflowState.mComputedBorderPadding.top + focusPadding.top;
aDesiredSize.ascent +=
aReflowState.mComputedBorderPadding.top + focusPadding.top;
aDesiredSize.descent = aDesiredSize.height - aDesiredSize.ascent;
aDesiredSize.mOverflowArea = nsRect(0, 0, aDesiredSize.width, aDesiredSize.height);
aDesiredSize.mOverflowArea =
nsRect(0, 0, aDesiredSize.width, aDesiredSize.height);
ConsiderChildOverflow(aDesiredSize.mOverflowArea, firstKid);
FinishAndStoreOverflow(&aDesiredSize);
aStatus = NS_FRAME_COMPLETE;
nsFormControlFrame::SetupCachedSizes(mCacheSize, mCachedAscent,
mCachedMaxElementWidth, aDesiredSize);
NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
return NS_OK;
}
@@ -378,25 +363,48 @@ nsHTMLButtonControlFrame::ReflowButtonContents(nsPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsIFrame* aFirstKid,
const nsSize& aAvailSize,
nsReflowReason aReason,
nsMargin aFocusPadding,
nsReflowStatus& aStatus)
{
nsHTMLReflowState reflowState(aPresContext, aReflowState, aFirstKid, aAvailSize, aReason);
nsSize availSize(aReflowState.mComputedWidth, NS_INTRINSICSIZE);
// Indent the child inside us by the focus border. We must do this separate
// from the regular border.
availSize.width -= aFocusPadding.LeftRight();
availSize.width = PR_MAX(availSize.width,0);
// See whether out availSize's width is big enough. If it's smaller than our
// intrinsic min width, that means that the kid wouldn't really fit; for a
// better look in such cases we adjust the available width and our left
// offset to allow the kid to spill left into our padding.
nscoord xoffset = aFocusPadding.left + aReflowState.mComputedBorderPadding.left;
nscoord extrawidth = DoGetMinWidth(aReflowState.rendContext, PR_FALSE) -
aReflowState.mComputedWidth;
if (extrawidth > 0) {
nscoord extraleft = extrawidth / 2;
nscoord extraright = extrawidth - extraleft;
NS_ASSERTION(extraright >=0, "How'd that happen?");
// Do not allow the extras to be bigger than the relevant padding
extraleft = PR_MIN(extraleft, aReflowState.mComputedPadding.left);
extraright = PR_MIN(extraright, aReflowState.mComputedPadding.right);
xoffset -= extraleft;
availSize.width += extraleft + extraright;
}
nsHTMLReflowState reflowState(aPresContext, aReflowState, aFirstKid,
availSize);
ReflowChild(aFirstKid, aPresContext, aDesiredSize, reflowState,
aFocusPadding.left + aReflowState.mComputedBorderPadding.left,
xoffset,
aFocusPadding.top + aReflowState.mComputedBorderPadding.top,
0, aStatus);
// calculate the min internal size so the contents gets centered correctly
// minInternalWidth is not being used at all and causes a warning--commenting
// out until someone wants it.
// nscoord minInternalWidth = aReflowState.mComputedMinWidth == 0?0:aReflowState.mComputedMinWidth -
// (aReflowState.mComputedBorderPadding.left + aReflowState.mComputedBorderPadding.right);
nscoord minInternalHeight = aReflowState.mComputedMinHeight == 0?0:aReflowState.mComputedMinHeight -
(aReflowState.mComputedBorderPadding.top + aReflowState.mComputedBorderPadding.bottom);
// calculate the min internal height so the contents gets centered correctly.
// XXXbz this assumes border-box sizing.
nscoord minInternalHeight = aReflowState.mComputedMinHeight -
aReflowState.mComputedBorderPadding.TopBottom();
minInternalHeight = PR_MAX(minInternalHeight, 0);
// center child vertically
nscoord yoff = 0;
@@ -413,27 +421,6 @@ nsHTMLButtonControlFrame::ReflowButtonContents(nsPresContext* aPresContext,
// baseline by that much).
aDesiredSize.ascent += yoff;
// Place the child. If we have a non-intrinsic width, we want to
// reduce the left padding as needed to try and fit the text in the
// button
nscoord xoffset = aFocusPadding.left + aReflowState.mComputedBorderPadding.left;
if (aReflowState.mComputedWidth != NS_INTRINSICSIZE) {
// First, how much did we "overflow"? This is the width of our
// kid plus our special focus stuff (which did not get accounted
// for in calculating aReflowState.mComputedWidth minus the width
// we're forced to be.
nscoord extrawidth =
aDesiredSize.width + aFocusPadding.left + aFocusPadding.right
- aReflowState.mComputedWidth;
if (extrawidth > 0) {
// Split it evenly between right and left
extrawidth /= 2;
// But do not shoot out the left side of the button, please
extrawidth = PR_MIN(extrawidth, aReflowState.mComputedPadding.left);
xoffset -= extrawidth;
}
}
// Place the child
FinishReflowChild(aFirstKid, aPresContext, &reflowState, aDesiredSize,
xoffset,
@@ -506,3 +493,9 @@ nsHTMLButtonControlFrame::RemoveFrame(nsIAtom* aListName,
NS_NOTREACHED("unsupported operation");
return NS_ERROR_UNEXPECTED;
}
PRBool
nsHTMLButtonControlFrame::IsFrameOfType(PRUint32 aFlags) const
{
return !(aFlags & ~(eReplaced | eReplacedContainsBlock));
}