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:
parent
c863ba7cc4
commit
ccd0e3e698
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user