mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-01 00:32:11 +00:00
Bug 1393116 - Move double-reflow for sizing-to-content one level lower r=dbaron
After the fix to bug 1294442 and bug 1324499, ResizeReflow began to be called twice for each DOM update in webext popups, and we also artificially re-set the scroll outside of ResizeReflow to counter the DidDoReflow callback in nsHTMLScrollFrame setting scrolltop to zero due to the first reflow, which is done with unconstrained height. Because of the scrollport being reset we get spurious DOM scroll events. Replacing the scrollport also interrupts smooth scrolling. Move the double-reflow down one level into PresShell, doing it before DidDoReflow is called. The scrollport is no longer reset (causing a spurious scroll event), and we don't need to replace it (interrupting smooth scrolling). Also partially fixes bug 1396034. MozReview-Commit-ID: HzYITyH4UeW --HG-- extra : rebase_source : 567056300bc81c9e4c197783f48636caf67cde34 extra : intermediate-source : ef7322dfd99d79a403bb0804638a46c70ece1b45 extra : source : 4f1761bb955473026b4deba76a5e76e93b7ede35
This commit is contained in:
parent
71c9765002
commit
bdd58219ae
@ -1868,7 +1868,8 @@ PresShell::AsyncResizeEventCallback(nsITimer* aTimer, void* aPresShell)
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight, nscoord aOldWidth, nscoord aOldHeight)
|
||||
PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight, nscoord aOldWidth,
|
||||
nscoord aOldHeight, ResizeReflowOptions aOptions)
|
||||
{
|
||||
if (mZoomConstraintsClient) {
|
||||
// If we have a ZoomConstraintsClient and the available screen area
|
||||
@ -1884,39 +1885,58 @@ PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight, nscoord aOldWidth, nsco
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return ResizeReflowIgnoreOverride(aWidth, aHeight, aOldWidth, aOldHeight);
|
||||
return ResizeReflowIgnoreOverride(aWidth, aHeight, aOldWidth,
|
||||
aOldHeight, aOptions);
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresShell::ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight, nscoord aOldWidth, nscoord aOldHeight)
|
||||
PresShell::ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight,
|
||||
nscoord aOldWidth, nscoord aOldHeight,
|
||||
ResizeReflowOptions aOptions)
|
||||
{
|
||||
NS_PRECONDITION(!mIsReflowing, "Shouldn't be in reflow here!");
|
||||
|
||||
// If we don't have a root frame yet, that means we haven't had our initial
|
||||
// reflow... If that's the case, and aWidth or aHeight is unconstrained,
|
||||
// ignore them altogether.
|
||||
nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
|
||||
if (!rootFrame &&
|
||||
(aHeight == NS_UNCONSTRAINEDSIZE || aWidth == NS_UNCONSTRAINEDSIZE)) {
|
||||
// We can't do the work needed for SizeToContent without a root
|
||||
// frame, and we want to return before setting the visible area.
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
mPresContext->SetVisibleArea(nsRect(0, 0, aWidth, aHeight));
|
||||
|
||||
// There isn't anything useful we can do if the initial reflow hasn't happened.
|
||||
if (!rootFrame) {
|
||||
// If we don't have a root frame yet, that means we haven't had our initial
|
||||
// reflow... If that's the case, and aWidth or aHeight is unconstrained,
|
||||
// ignore them altogether.
|
||||
if (aHeight == NS_UNCONSTRAINEDSIZE || aWidth == NS_UNCONSTRAINEDSIZE) {
|
||||
// We can't do the work needed for SizeToContent without a root
|
||||
// frame, and we want to return before setting the visible area.
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
mPresContext->SetVisibleArea(nsRect(0, 0, aWidth, aHeight));
|
||||
// There isn't anything useful we can do if the initial reflow hasn't
|
||||
// happened.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
WritingMode wm = rootFrame->GetWritingMode();
|
||||
NS_PRECONDITION((wm.IsVertical() ? aHeight : aWidth) != NS_UNCONSTRAINEDSIZE,
|
||||
"shouldn't use unconstrained isize anymore");
|
||||
const bool shrinkToFit = aOptions == ResizeReflowOptions::eBSizeLimit;
|
||||
NS_PRECONDITION(shrinkToFit ||
|
||||
(wm.IsVertical() ? aWidth : aHeight) !=
|
||||
NS_UNCONSTRAINEDSIZE,
|
||||
"unconstrained bsize only usable with eBSizeLimit");
|
||||
NS_PRECONDITION((wm.IsVertical() ? aHeight : aWidth) !=
|
||||
NS_UNCONSTRAINEDSIZE,
|
||||
"unconstrained isize not allowed");
|
||||
bool isBSizeChanging = wm.IsVertical() ? aOldWidth != aWidth
|
||||
: aOldHeight != aHeight;
|
||||
nscoord targetWidth = aWidth;
|
||||
nscoord targetHeight = aHeight;
|
||||
|
||||
const bool isBSizeChanging = wm.IsVertical()
|
||||
? aOldWidth != aWidth
|
||||
: aOldHeight != aHeight;
|
||||
if (shrinkToFit) {
|
||||
if (wm.IsVertical()) {
|
||||
targetWidth = NS_UNCONSTRAINEDSIZE;
|
||||
} else {
|
||||
targetHeight = NS_UNCONSTRAINEDSIZE;
|
||||
}
|
||||
isBSizeChanging = true;
|
||||
}
|
||||
|
||||
mPresContext->SetVisibleArea(nsRect(0, 0, targetWidth, targetHeight));
|
||||
|
||||
RefPtr<nsViewManager> viewManager = mViewManager;
|
||||
nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
|
||||
@ -1955,8 +1975,29 @@ PresShell::ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight, nscoord a
|
||||
|
||||
mDirtyRoots.RemoveElement(rootFrame);
|
||||
DoReflow(rootFrame, true);
|
||||
|
||||
if (shrinkToFit) {
|
||||
const bool reflowAgain = wm.IsVertical() ?
|
||||
mPresContext->GetVisibleArea().width > aWidth :
|
||||
mPresContext->GetVisibleArea().height > aHeight;
|
||||
|
||||
if (reflowAgain) {
|
||||
mPresContext->SetVisibleArea(nsRect(0, 0, aWidth, aHeight));
|
||||
DoReflow(rootFrame, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// the first DoReflow above should've set our bsize if it was
|
||||
// NS_UNCONSTRAINEDSIZE, and the isize shouldn't be NS_UNCONSTRAINEDSIZE
|
||||
// anyway
|
||||
NS_ASSERTION(
|
||||
mPresContext->GetVisibleArea().width != NS_UNCONSTRAINEDSIZE,
|
||||
"width should not be NS_UNCONSTRAINEDSIZE after reflow");
|
||||
NS_ASSERTION(
|
||||
mPresContext->GetVisibleArea().height != NS_UNCONSTRAINEDSIZE,
|
||||
"height should not be NS_UNCONSTRAINEDSIZE after reflow");
|
||||
|
||||
DidDoReflow(true);
|
||||
}
|
||||
}
|
||||
@ -1964,13 +2005,16 @@ PresShell::ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight, nscoord a
|
||||
rootFrame = mFrameConstructor->GetRootFrame();
|
||||
if (rootFrame) {
|
||||
wm = rootFrame->GetWritingMode();
|
||||
// reflow did not happen; if the reflow happened, our bsize should not be
|
||||
// NS_UNCONSTRAINEDSIZE because DoReflow will fix it up to the same values
|
||||
// as below
|
||||
if (wm.IsVertical()) {
|
||||
if (aWidth == NS_UNCONSTRAINEDSIZE) {
|
||||
if (mPresContext->GetVisibleArea().width == NS_UNCONSTRAINEDSIZE) {
|
||||
mPresContext->SetVisibleArea(
|
||||
nsRect(0, 0, rootFrame->GetRect().width, aHeight));
|
||||
}
|
||||
} else {
|
||||
if (aHeight == NS_UNCONSTRAINEDSIZE) {
|
||||
if (mPresContext->GetVisibleArea().height == NS_UNCONSTRAINEDSIZE) {
|
||||
mPresContext->SetVisibleArea(
|
||||
nsRect(0, 0, aWidth, rootFrame->GetRect().height));
|
||||
}
|
||||
|
@ -111,8 +111,14 @@ public:
|
||||
virtual void BeginObservingDocument() override;
|
||||
virtual void EndObservingDocument() override;
|
||||
virtual nsresult Initialize(nscoord aWidth, nscoord aHeight) override;
|
||||
virtual nsresult ResizeReflow(nscoord aWidth, nscoord aHeight, nscoord aOldWidth = 0, nscoord aOldHeight = 0) override;
|
||||
virtual nsresult ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight, nscoord aOldWidth, nscoord aOldHeight) override;
|
||||
virtual nsresult ResizeReflow(nscoord aWidth, nscoord aHeight,
|
||||
nscoord aOldWidth = 0, nscoord aOldHeight = 0,
|
||||
ResizeReflowOptions aOptions =
|
||||
ResizeReflowOptions::eBSizeExact) override;
|
||||
virtual nsresult ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight,
|
||||
nscoord aOldWidth, nscoord aOldHeight,
|
||||
ResizeReflowOptions aOptions =
|
||||
ResizeReflowOptions::eBSizeExact) override;
|
||||
virtual nsIPageSequenceFrame* GetPageSequenceFrame() const override;
|
||||
virtual nsCanvasFrame* GetCanvasFrame() const override;
|
||||
|
||||
|
@ -3508,37 +3508,16 @@ nsDocumentViewer::GetContentSizeInternal(int32_t* aWidth, int32_t* aHeight,
|
||||
prefWidth = aMaxWidth;
|
||||
}
|
||||
|
||||
nsAutoPtr<nsPresState> frameState;
|
||||
nsIScrollableFrame *scrollFrame = presShell->GetRootScrollFrameAsScrollable();
|
||||
nsIStatefulFrame *statefulFrame = do_QueryFrame(scrollFrame);
|
||||
if (statefulFrame) {
|
||||
statefulFrame->SaveState(getter_Transfers(frameState));
|
||||
}
|
||||
|
||||
nsresult rv = presShell->ResizeReflow(prefWidth, NS_UNCONSTRAINEDSIZE);
|
||||
nsresult rv = presShell->ResizeReflow(prefWidth, aMaxHeight, 0, 0,
|
||||
nsIPresShell::ResizeReflowOptions::eBSizeLimit);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
RefPtr<nsPresContext> presContext;
|
||||
GetPresContext(getter_AddRefs(presContext));
|
||||
NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
|
||||
|
||||
// so how big is it?
|
||||
nsRect shellArea = presContext->GetVisibleArea();
|
||||
if (shellArea.height > aMaxHeight) {
|
||||
// Reflow to max height if we would up too tall.
|
||||
rv = presShell->ResizeReflow(prefWidth, aMaxHeight);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
shellArea = presContext->GetVisibleArea();
|
||||
|
||||
// the first reflow reset our scroll, now set it back
|
||||
if (frameState && presShell->GetRootScrollFrameAsScrollable() == scrollFrame) {
|
||||
statefulFrame->RestoreState(frameState);
|
||||
scrollFrame->ScrollToRestoredPosition();
|
||||
}
|
||||
}
|
||||
|
||||
// Protect against bogus returns here
|
||||
nsRect shellArea = presContext->GetVisibleArea();
|
||||
NS_ENSURE_TRUE(shellArea.width != NS_UNCONSTRAINEDSIZE &&
|
||||
shellArea.height != NS_UNCONSTRAINEDSIZE,
|
||||
NS_ERROR_FAILURE);
|
||||
|
@ -359,16 +359,30 @@ public:
|
||||
*/
|
||||
virtual nsresult Initialize(nscoord aWidth, nscoord aHeight) = 0;
|
||||
|
||||
enum class ResizeReflowOptions : uint32_t {
|
||||
// the resulting BSize should be exactly as given
|
||||
eBSizeExact,
|
||||
// the resulting BSize can be less than the given one, producing
|
||||
// shrink-to-fit sizing in the block dimension
|
||||
eBSizeLimit
|
||||
};
|
||||
/**
|
||||
* Reflow the frame model into a new width and height. The
|
||||
* coordinates for aWidth and aHeight must be in standard nscoord's.
|
||||
*/
|
||||
virtual nsresult ResizeReflow(nscoord aWidth, nscoord aHeight, nscoord aOldWidth = 0, nscoord aOldHeight = 0) = 0;
|
||||
virtual nsresult ResizeReflow(nscoord aWidth, nscoord aHeight,
|
||||
nscoord aOldWidth = 0, nscoord aOldHeight = 0,
|
||||
ResizeReflowOptions aOptions =
|
||||
ResizeReflowOptions::eBSizeExact) = 0;
|
||||
/**
|
||||
* Do the same thing as ResizeReflow but even if ResizeReflowOverride was
|
||||
* called previously.
|
||||
*/
|
||||
virtual nsresult ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight, nscoord aOldWidth, nscoord aOldHeight) = 0;
|
||||
virtual nsresult ResizeReflowIgnoreOverride(
|
||||
nscoord aWidth, nscoord aHeight,
|
||||
nscoord aOldWidth, nscoord aOldHeight,
|
||||
ResizeReflowOptions aOptions =
|
||||
ResizeReflowOptions::eBSizeExact) = 0;
|
||||
|
||||
/**
|
||||
* Returns true if ResizeReflowOverride has been called.
|
||||
|
Loading…
Reference in New Issue
Block a user