Fixes the problem where PrintPreview is getting multiple Initial reflows

and includes a minor optimization when resizing the view during box layout
Bug 118968 r=attinasi sr=hyatt a=brendan


git-svn-id: svn://10.0.0.236/trunk@112569 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
rods%netscape.com 2002-01-23 02:53:02 +00:00
parent c863ba7cc4
commit ccd0e3e698
5 changed files with 173 additions and 3 deletions

View File

@ -70,6 +70,8 @@
#include "nsIGfxTextControlFrame.h"
#include "nsIDOMHTMLTextAreaElement.h"
#include "nsIPrintPreviewContext.h"
#include "nsIURI.h"
//----------------------------------------------------------------------
@ -178,6 +180,8 @@ public:
NS_IMETHOD GetScrolledSize(nsIPresContext* aPresContext,
nscoord *aWidth,
nscoord *aHeight) const;
void AdjustReflowStateForPrintPreview(nsBoxLayoutState& aState, PRBool& aSetBack);
void AdjustReflowStateBack(nsBoxLayoutState& aState, PRBool aSetBack);
nsIBox* mHScrollbarBox;
nsIBox* mVScrollbarBox;
@ -1079,6 +1083,54 @@ nsGfxScrollFrame::DoLayout(nsBoxLayoutState& aState)
return rv;
}
/**
* When reflowing a HTML document where the content model is being created
* The nsGfxScrollFrame will get an Initial reflow when the body is opened by the content sink.
* But there isn't enough content to really reflow very much of the document
* so it never needs to do layout for the scrollbars
*
* So later other reflows happen and these are Incremental reflows, and then the scrollbars
* get reflowed. The important point here is that when they reflowed the ReflowState inside the
* BoxLayoutState contains an "Incremental" reason and never a "Initial" reason.
*
* When it reflows for Print Preview, the content model is already full constructed and it lays
* out the entire document at that time. When it returns back here it discovers it needs scrollbars
* and this is a problem because the ReflowState inside the BoxLayoutState still has a "Initial"
* reason and if it does a Layout it is essentially asking everything to reflow yet again with
* an "Initial" reason. This causes a lot of problems especially for tables.
*
* The solution for this is to change the ReflowState's reason from Initial to Resize and let
* all the frames do what is necessary for a resize refow. Now, we only need to do this when
* it is doing PrintPreview and we need only do it for HTML documents and NOT chrome.
*
*/
void
nsGfxScrollFrameInner::AdjustReflowStateForPrintPreview(nsBoxLayoutState& aState, PRBool& aSetBack)
{
aSetBack = PR_FALSE;
PRBool isChrome;
PRBool isInitialPP = nsBoxFrame::IsInitialReflowForPrintPreview(aState, isChrome);
if (isInitialPP && !isChrome) {
// I know you shouldn't, but we cast away the "const" here
nsHTMLReflowState* reflowState = (nsHTMLReflowState*)aState.GetReflowState();
reflowState->reason = eReflowReason_Resize;
aSetBack = PR_TRUE;
}
}
/**
* Sets reflow state back to Initial when we are done.
*/
void
nsGfxScrollFrameInner::AdjustReflowStateBack(nsBoxLayoutState& aState, PRBool aSetBack)
{
// I know you shouldn't, but we cast away the "const" here
nsHTMLReflowState* reflowState = (nsHTMLReflowState*)aState.GetReflowState();
if (aSetBack && reflowState->reason == eReflowReason_Resize) {
reflowState->reason = eReflowReason_Initial;
}
}
/**
* Reflow the scroll area if it needs it and return its size. Also determine if the reflow will
* cause any of the scrollbars to need to be reflowed.
@ -1206,7 +1258,10 @@ nsGfxScrollFrameInner::Layout(nsBoxLayoutState& aState)
if (needsLayout) {
nsBoxLayoutState resizeState(aState);
resizeState.SetLayoutReason(nsBoxLayoutState::Resize);
PRBool setBack;
AdjustReflowStateForPrintPreview(aState, setBack);
LayoutBox(resizeState, mScrollAreaBox, scrollAreaRect);
AdjustReflowStateBack(aState, setBack);
needsLayout = PR_FALSE;
}
}
@ -1267,7 +1322,10 @@ nsGfxScrollFrameInner::Layout(nsBoxLayoutState& aState)
if (needsLayout) {
nsBoxLayoutState resizeState(aState);
resizeState.SetLayoutReason(nsBoxLayoutState::Resize);
PRBool setBack;
AdjustReflowStateForPrintPreview(aState, setBack);
LayoutBox(resizeState, mScrollAreaBox, scrollAreaRect);
AdjustReflowStateBack(aState, setBack);
needsLayout = PR_FALSE;
#ifdef IBMBIDI
reflowState->mRightEdge = NS_UNCONSTRAINEDSIZE;

View File

@ -70,6 +70,8 @@
#include "nsIGfxTextControlFrame.h"
#include "nsIDOMHTMLTextAreaElement.h"
#include "nsIPrintPreviewContext.h"
#include "nsIURI.h"
//----------------------------------------------------------------------
@ -178,6 +180,8 @@ public:
NS_IMETHOD GetScrolledSize(nsIPresContext* aPresContext,
nscoord *aWidth,
nscoord *aHeight) const;
void AdjustReflowStateForPrintPreview(nsBoxLayoutState& aState, PRBool& aSetBack);
void AdjustReflowStateBack(nsBoxLayoutState& aState, PRBool aSetBack);
nsIBox* mHScrollbarBox;
nsIBox* mVScrollbarBox;
@ -1079,6 +1083,54 @@ nsGfxScrollFrame::DoLayout(nsBoxLayoutState& aState)
return rv;
}
/**
* When reflowing a HTML document where the content model is being created
* The nsGfxScrollFrame will get an Initial reflow when the body is opened by the content sink.
* But there isn't enough content to really reflow very much of the document
* so it never needs to do layout for the scrollbars
*
* So later other reflows happen and these are Incremental reflows, and then the scrollbars
* get reflowed. The important point here is that when they reflowed the ReflowState inside the
* BoxLayoutState contains an "Incremental" reason and never a "Initial" reason.
*
* When it reflows for Print Preview, the content model is already full constructed and it lays
* out the entire document at that time. When it returns back here it discovers it needs scrollbars
* and this is a problem because the ReflowState inside the BoxLayoutState still has a "Initial"
* reason and if it does a Layout it is essentially asking everything to reflow yet again with
* an "Initial" reason. This causes a lot of problems especially for tables.
*
* The solution for this is to change the ReflowState's reason from Initial to Resize and let
* all the frames do what is necessary for a resize refow. Now, we only need to do this when
* it is doing PrintPreview and we need only do it for HTML documents and NOT chrome.
*
*/
void
nsGfxScrollFrameInner::AdjustReflowStateForPrintPreview(nsBoxLayoutState& aState, PRBool& aSetBack)
{
aSetBack = PR_FALSE;
PRBool isChrome;
PRBool isInitialPP = nsBoxFrame::IsInitialReflowForPrintPreview(aState, isChrome);
if (isInitialPP && !isChrome) {
// I know you shouldn't, but we cast away the "const" here
nsHTMLReflowState* reflowState = (nsHTMLReflowState*)aState.GetReflowState();
reflowState->reason = eReflowReason_Resize;
aSetBack = PR_TRUE;
}
}
/**
* Sets reflow state back to Initial when we are done.
*/
void
nsGfxScrollFrameInner::AdjustReflowStateBack(nsBoxLayoutState& aState, PRBool aSetBack)
{
// I know you shouldn't, but we cast away the "const" here
nsHTMLReflowState* reflowState = (nsHTMLReflowState*)aState.GetReflowState();
if (aSetBack && reflowState->reason == eReflowReason_Resize) {
reflowState->reason = eReflowReason_Initial;
}
}
/**
* Reflow the scroll area if it needs it and return its size. Also determine if the reflow will
* cause any of the scrollbars to need to be reflowed.
@ -1206,7 +1258,10 @@ nsGfxScrollFrameInner::Layout(nsBoxLayoutState& aState)
if (needsLayout) {
nsBoxLayoutState resizeState(aState);
resizeState.SetLayoutReason(nsBoxLayoutState::Resize);
PRBool setBack;
AdjustReflowStateForPrintPreview(aState, setBack);
LayoutBox(resizeState, mScrollAreaBox, scrollAreaRect);
AdjustReflowStateBack(aState, setBack);
needsLayout = PR_FALSE;
}
}
@ -1267,7 +1322,10 @@ nsGfxScrollFrameInner::Layout(nsBoxLayoutState& aState)
if (needsLayout) {
nsBoxLayoutState resizeState(aState);
resizeState.SetLayoutReason(nsBoxLayoutState::Resize);
PRBool setBack;
AdjustReflowStateForPrintPreview(aState, setBack);
LayoutBox(resizeState, mScrollAreaBox, scrollAreaRect);
AdjustReflowStateBack(aState, setBack);
needsLayout = PR_FALSE;
#ifdef IBMBIDI
reflowState->mRightEdge = NS_UNCONSTRAINEDSIZE;

View File

@ -97,6 +97,12 @@
#include "nsIWidget.h"
#include "nsITheme.h"
// Needed for Print Preview
#include "nsIDocument.h"
#include "nsIPrintPreviewContext.h"
#include "nsIURI.h"
static NS_DEFINE_IID(kWidgetCID, NS_CHILD_CID);
//define DEBUG_REDRAW
@ -844,6 +850,38 @@ static void printSize(char * aDesc, nscoord aSize)
}
#endif
/**
* Returns PR_TRUE when the reflow reason is "Initial" and doing Print Preview
* when returning PR_FALSE aIsChrome's value is indeterminate
* aIsChrome - Returns PR_TRUE when document is chrome, otherwise PR_FALSE
*/
PRBool
nsBoxFrame::IsInitialReflowForPrintPreview(nsBoxLayoutState& aState,
PRBool& aIsChrome)
{
aIsChrome = PR_FALSE;
const nsHTMLReflowState* reflowState = aState.GetReflowState();
if (reflowState->reason == eReflowReason_Initial) {
// See if we are doing Print Preview
nsCOMPtr<nsIPrintPreviewContext> ppContent(do_QueryInterface(aState.GetPresContext()));
if (ppContent) {
// Now, get the current URI to see of we doing chrome
nsCOMPtr<nsIPresShell> presShell;
aState.GetPresContext()->GetShell(getter_AddRefs(presShell));
if (!presShell) return PR_FALSE;
nsCOMPtr<nsIDocument> doc;
presShell->GetDocument(getter_AddRefs(doc));
if (!doc) return PR_FALSE;
nsCOMPtr<nsIURI> uri;
doc->GetDocumentURL(getter_AddRefs(uri));
if (!uri) return PR_FALSE;
uri->SchemeIs("chrome", &aIsChrome);
return PR_TRUE;
}
}
return PR_FALSE;
}
NS_IMETHODIMP
nsBoxFrame::Reflow(nsIPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
@ -957,8 +995,17 @@ nsBoxFrame::Reflow(nsIPresContext* aPresContext,
// getting the ascent could be a lot of work. Don't get it if
// we are the root. The viewport doesn't care about it.
if (!(mState & NS_STATE_IS_ROOT))
GetAscent(state, ascent);
if (!(mState & NS_STATE_IS_ROOT)) {
// Only call GetAscent when not doing Initial reflow while in PP
// or when it is Initial reflow while in PP and a chrome doc
// If called again with initial reflow it crashes because the
// frames are fully constructed (I think).
PRBool isChrome;
PRBool isInitialPP = IsInitialReflowForPrintPreview(state, isChrome);
if (!isInitialPP || (isInitialPP && isChrome)) {
GetAscent(state, ascent);
}
}
aDesiredSize.width = r.width;
aDesiredSize.height = r.height;

View File

@ -205,6 +205,9 @@ public:
nsFramePaintLayer aWhichLayer,
PRUint32 aFlags = 0);
// returns true if it is an Initial Reflow and doing Print Preview
static PRBool IsInitialReflowForPrintPreview(nsBoxLayoutState& aState, PRBool& aIsChrome);
protected:
virtual void GetBoxName(nsAutoString& aName);

View File

@ -429,7 +429,11 @@ nsScrollBoxFrame::DoLayout(nsBoxLayoutState& aState)
nsCOMPtr<nsIViewManager> vm;
view->GetViewManager(*getter_AddRefs(vm));
nsRect r(0, 0, childRect.width, childRect.height);
vm->ResizeView(view, r);
nsRect bnds;
view->GetBounds(bnds);
if (bnds != r) {
vm->ResizeView(view, r);
}
}
nsIScrollableView* scrollingView;