Bug 1583534 - Further simplify PresShell::ResizeReflow. r=botond

In particular, not let ResizeReflow take the old and new size. Most of the
callers pass dummy values anyway.

Instead, use the old size of the layout viewport. This ensures we fire resize
events only if the layout viewport actually changes.

This is important because the first resize of the mobile viewport manager
after a navigation has an "old size" of 0x0, even though the layout viewport
is initialized on presshell initialization to the right size.

Thus, we fire resize events unnecessarily in that case, which is the root cause
for bug 1528052.

To do this, we need to shuffle a bit of code in nsDocumentViewer that deals with
delayed resizes, to set the visible area _and_ invalidate layout, rather than
setting the visible area and _then_ relying on doing a resize reflow.

Further cleanup is possible, though not required for my android resizing fix, so
will do separately.

Differential Revision: https://phabricator.services.mozilla.com/D46944

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Emilio Cobos Álvarez 2019-09-25 19:12:44 +00:00
Родитель b12c4363fb
Коммит 848d89d65f
12 изменённых файлов: 50 добавлений и 49 удалений

Просмотреть файл

@ -3852,6 +3852,11 @@ void nsGlobalWindowOuter::SetCSSViewportWidthAndHeight(nscoord aInnerWidth,
shellArea.SetHeight(aInnerHeight); shellArea.SetHeight(aInnerHeight);
shellArea.SetWidth(aInnerWidth); shellArea.SetWidth(aInnerWidth);
// FIXME(emilio): This doesn't seem to be ok, this doesn't reflow or
// anything... Should go through PresShell::ResizeReflow.
//
// But I don't think this can be reached by content, as we don't allow to set
// inner{Width,Height}.
presContext->SetVisibleArea(shellArea); presContext->SetVisibleArea(shellArea);
} }

Просмотреть файл

@ -82,8 +82,7 @@ class MockMVMContext : public MVMContext {
mResolution = aResolution; mResolution = aResolution;
mMVM->ResolutionUpdated(aOrigin); mMVM->ResolutionUpdated(aOrigin);
} }
void Reflow(const CSSSize& aNewSize, const CSSSize& aOldSize, void Reflow(const CSSSize& aNewSize, ResizeEventFlag) {
ResizeEventFlag aResizeEventFlag) {
mICBSize = aNewSize; mICBSize = aNewSize;
mContentSize = mLayoutFunction(mICBSize); mContentSize = mLayoutFunction(mICBSize);
} }

Просмотреть файл

@ -176,7 +176,7 @@ void GeckoMVMContext::UpdateDisplayPortMargins() {
} }
} }
void GeckoMVMContext::Reflow(const CSSSize& aNewSize, const CSSSize& aOldSize, void GeckoMVMContext::Reflow(const CSSSize& aNewSize,
ResizeEventFlag aResizeEventFlag) { ResizeEventFlag aResizeEventFlag) {
MOZ_ASSERT(mPresShell); MOZ_ASSERT(mPresShell);
@ -189,8 +189,7 @@ void GeckoMVMContext::Reflow(const CSSSize& aNewSize, const CSSSize& aOldSize,
presShell->ResizeReflowIgnoreOverride( presShell->ResizeReflowIgnoreOverride(
nsPresContext::CSSPixelsToAppUnits(aNewSize.width), nsPresContext::CSSPixelsToAppUnits(aNewSize.width),
nsPresContext::CSSPixelsToAppUnits(aNewSize.height), nsPresContext::CSSPixelsToAppUnits(aNewSize.height),
nsPresContext::CSSPixelsToAppUnits(aOldSize.width), reflowOptions);
nsPresContext::CSSPixelsToAppUnits(aOldSize.height), reflowOptions);
} }
} // namespace mozilla } // namespace mozilla

Просмотреть файл

@ -55,8 +55,7 @@ class GeckoMVMContext : public MVMContext {
void SetVisualViewportSize(const CSSSize& aSize) override; void SetVisualViewportSize(const CSSSize& aSize) override;
void UpdateDisplayPortMargins() override; void UpdateDisplayPortMargins() override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY MOZ_CAN_RUN_SCRIPT_BOUNDARY
void Reflow(const CSSSize& aNewSize, const CSSSize& aOldSize, void Reflow(const CSSSize& aNewSize, ResizeEventFlag) override;
ResizeEventFlag aResizeEventFlag) override;
private: private:
RefPtr<dom::Document> mDocument; RefPtr<dom::Document> mDocument;

Просмотреть файл

@ -63,8 +63,7 @@ class MVMContext {
IfNecessary, // resize events will be fired if necessary. IfNecessary, // resize events will be fired if necessary.
Suppress, // resize events will never be fired. Suppress, // resize events will never be fired.
}; };
virtual void Reflow(const CSSSize& aNewSize, const CSSSize& aOldSize, virtual void Reflow(const CSSSize& aNewSize, ResizeEventFlag) = 0;
ResizeEventFlag aResizeEventFlag) = 0;
}; };
} // namespace mozilla } // namespace mozilla

Просмотреть файл

@ -589,15 +589,13 @@ void MobileViewportManager::RefreshViewportSize(bool aForceAdjustResolution) {
UpdateDisplayPortMargins(); UpdateDisplayPortMargins();
} }
CSSSize oldSize = mMobileViewportSize;
// Update internal state. // Update internal state.
mMobileViewportSize = viewport; mMobileViewportSize = viewport;
RefPtr<MobileViewportManager> strongThis(this); RefPtr<MobileViewportManager> strongThis(this);
// Kick off a reflow. // Kick off a reflow.
mContext->Reflow(viewport, oldSize, mContext->Reflow(viewport,
mIsFirstPaint ? MVMContext::ResizeEventFlag::Suppress mIsFirstPaint ? MVMContext::ResizeEventFlag::Suppress
: MVMContext::ResizeEventFlag::IfNecessary); : MVMContext::ResizeEventFlag::IfNecessary);

Просмотреть файл

@ -1838,7 +1838,6 @@ void PresShell::sPaintSuppressionCallback(nsITimer* aTimer, void* aPresShell) {
} }
nsresult PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight, nsresult PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight,
nscoord aOldWidth, nscoord aOldHeight,
ResizeReflowOptions aOptions) { ResizeReflowOptions aOptions) {
if (mZoomConstraintsClient) { if (mZoomConstraintsClient) {
// If we have a ZoomConstraintsClient and the available screen area // If we have a ZoomConstraintsClient and the available screen area
@ -1856,14 +1855,14 @@ nsresult PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight,
return NS_OK; return NS_OK;
} }
return ResizeReflowIgnoreOverride(aWidth, aHeight, aOldWidth, aOldHeight, return ResizeReflowIgnoreOverride(aWidth, aHeight, aOptions);
aOptions);
} }
void PresShell::SimpleResizeReflow(nscoord aWidth, nscoord aHeight, void PresShell::SimpleResizeReflow(nscoord aWidth, nscoord aHeight,
nscoord aOldWidth, nscoord aOldHeight) { ResizeReflowOptions aOptions) {
MOZ_ASSERT(aWidth != NS_UNCONSTRAINEDSIZE); MOZ_ASSERT(aWidth != NS_UNCONSTRAINEDSIZE);
MOZ_ASSERT(aHeight != NS_UNCONSTRAINEDSIZE); MOZ_ASSERT(aHeight != NS_UNCONSTRAINEDSIZE);
nsSize oldSize = mPresContext->GetVisibleArea().Size();
mPresContext->SetVisibleArea(nsRect(0, 0, aWidth, aHeight)); mPresContext->SetVisibleArea(nsRect(0, 0, aWidth, aHeight));
nsIFrame* rootFrame = GetRootFrame(); nsIFrame* rootFrame = GetRootFrame();
if (!rootFrame) { if (!rootFrame) {
@ -1871,7 +1870,7 @@ void PresShell::SimpleResizeReflow(nscoord aWidth, nscoord aHeight,
} }
WritingMode wm = rootFrame->GetWritingMode(); WritingMode wm = rootFrame->GetWritingMode();
bool isBSizeChanging = bool isBSizeChanging =
wm.IsVertical() ? aOldWidth != aWidth : aOldHeight != aHeight; wm.IsVertical() ? oldSize.width != aWidth : oldSize.height != aHeight;
if (isBSizeChanging) { if (isBSizeChanging) {
nsLayoutUtils::MarkIntrinsicISizesDirtyIfDependentOnBSize(rootFrame); nsLayoutUtils::MarkIntrinsicISizesDirtyIfDependentOnBSize(rootFrame);
} }
@ -1880,18 +1879,18 @@ void PresShell::SimpleResizeReflow(nscoord aWidth, nscoord aHeight,
// For compat with the old code path which always reflowed as long as there // For compat with the old code path which always reflowed as long as there
// was a root frame. // was a root frame.
if (!mPresContext->SuppressingResizeReflow()) { bool suppressReflow = (aOptions & ResizeReflowOptions::SuppressReflow) ||
mPresContext->SuppressingResizeReflow();
if (!suppressReflow) {
mDocument->FlushPendingNotifications(FlushType::InterruptibleLayout); mDocument->FlushPendingNotifications(FlushType::InterruptibleLayout);
} }
} }
nsresult PresShell::ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight, nsresult PresShell::ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight,
nscoord aOldWidth,
nscoord aOldHeight,
ResizeReflowOptions aOptions) { ResizeReflowOptions aOptions) {
MOZ_ASSERT(!mIsReflowing, "Shouldn't be in reflow here!"); MOZ_ASSERT(!mIsReflowing, "Shouldn't be in reflow here!");
nsSize oldSize = mPresContext->GetVisibleArea().Size();
if (aWidth == aOldWidth && aHeight == aOldHeight) { if (oldSize == nsSize(aWidth, aHeight)) {
return NS_OK; return NS_OK;
} }
@ -1911,12 +1910,13 @@ nsresult PresShell::ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight,
}; };
if (!(aOptions & ResizeReflowOptions::BSizeLimit)) { if (!(aOptions & ResizeReflowOptions::BSizeLimit)) {
SimpleResizeReflow(aWidth, aHeight, aOldWidth, aOldHeight); SimpleResizeReflow(aWidth, aHeight, aOptions);
postResizeEventIfNeeded(); postResizeEventIfNeeded();
return NS_OK; return NS_OK;
} }
MOZ_ASSERT(!mPresContext->SuppressingResizeReflow(), MOZ_ASSERT(!mPresContext->SuppressingResizeReflow() &&
!(aOptions & ResizeReflowOptions::SuppressReflow),
"Can't suppress resize reflow and shrink-wrap at the same time"); "Can't suppress resize reflow and shrink-wrap at the same time");
// Make sure that style is flushed before setting the pres context // Make sure that style is flushed before setting the pres context

Просмотреть файл

@ -344,20 +344,17 @@ class PresShell final : public nsStubDocumentObserver,
* coordinates for aWidth and aHeight must be in standard nscoord's. * coordinates for aWidth and aHeight must be in standard nscoord's.
*/ */
MOZ_CAN_RUN_SCRIPT nsresult MOZ_CAN_RUN_SCRIPT nsresult
ResizeReflow(nscoord aWidth, nscoord aHeight, nscoord aOldWidth = 0, ResizeReflow(nscoord aWidth, nscoord aHeight,
nscoord aOldHeight = 0, ResizeReflowOptions = ResizeReflowOptions::NoOption);
ResizeReflowOptions aOptions = ResizeReflowOptions::NoOption);
MOZ_CAN_RUN_SCRIPT nsresult ResizeReflowIgnoreOverride( MOZ_CAN_RUN_SCRIPT nsresult ResizeReflowIgnoreOverride(
nscoord aWidth, nscoord aHeight, nscoord aOldWidth, nscoord aOldHeight, nscoord aWidth, nscoord aHeight, ResizeReflowOptions);
ResizeReflowOptions aOptions = ResizeReflowOptions::NoOption);
private: private:
/** /**
* This is what ResizeReflowIgnoreOverride does when not shrink-wrapping (that * This is what ResizeReflowIgnoreOverride does when not shrink-wrapping (that
* is, when ResizeReflowOptions::BSizeLimit is not specified). * is, when ResizeReflowOptions::BSizeLimit is not specified).
*/ */
void SimpleResizeReflow(nscoord aWidth, nscoord aHeight, nscoord aOldWidth, void SimpleResizeReflow(nscoord aWidth, nscoord aHeight, ResizeReflowOptions);
nscoord aOldHeight);
public: public:
/** /**

Просмотреть файл

@ -41,6 +41,12 @@ enum class ResizeReflowOptions : uint32_t {
// additional reflow to zoom the content by the initial-scale or auto scaling // additional reflow to zoom the content by the initial-scale or auto scaling
// and we don't want any resize events during the initial paint. // and we don't want any resize events during the initial paint.
SuppressResizeEvent = 1 << 1, SuppressResizeEvent = 1 << 1,
// Invalidate layout, but don't reflow.
//
// TODO(emilio): Ideally this should just become the default, or we should
// unconditionally not reflow and rely on the caller to do so, having a
// separate API for shrink-to-fit.
SuppressReflow = 1 << 2,
}; };
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(ResizeReflowOptions) MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(ResizeReflowOptions)

Просмотреть файл

@ -3176,7 +3176,7 @@ nsresult nsDocumentViewer::GetContentSizeInternal(int32_t* aWidth,
prefWidth = aMaxWidth; prefWidth = aMaxWidth;
} }
nsresult rv = presShell->ResizeReflow(prefWidth, aMaxHeight, 0, 0, nsresult rv = presShell->ResizeReflow(prefWidth, aMaxHeight,
ResizeReflowOptions::BSizeLimit); ResizeReflowOptions::BSizeLimit);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);

Просмотреть файл

@ -171,16 +171,22 @@ void nsViewManager::GetWindowDimensions(nscoord* aWidth, nscoord* aHeight) {
} }
} }
void nsViewManager::DoSetWindowDimensions(nscoord aWidth, nscoord aHeight) { void nsViewManager::DoSetWindowDimensions(nscoord aWidth, nscoord aHeight,
bool aDoReflow) {
nsRect oldDim = mRootView->GetDimensions(); nsRect oldDim = mRootView->GetDimensions();
nsRect newDim(0, 0, aWidth, aHeight); nsRect newDim(0, 0, aWidth, aHeight);
// We care about resizes even when one dimension is already zero. // We care about resizes even when one dimension is already zero.
if (!oldDim.IsEqualEdges(newDim)) { if (oldDim.IsEqualEdges(newDim)) {
// Don't resize the widget. It is already being set elsewhere. return;
mRootView->SetDimensions(newDim, true, false); }
if (RefPtr<PresShell> presShell = mPresShell) { // Don't resize the widget. It is already being set elsewhere.
presShell->ResizeReflow(aWidth, aHeight, oldDim.Width(), oldDim.Height()); mRootView->SetDimensions(newDim, true, false);
if (RefPtr<PresShell> presShell = mPresShell) {
auto options = ResizeReflowOptions::NoOption;
if (!aDoReflow) {
options |= ResizeReflowOptions::SuppressReflow;
} }
presShell->ResizeReflow(aWidth, aHeight, options);
} }
} }
@ -213,7 +219,7 @@ void nsViewManager::SetWindowDimensions(nscoord aWidth, nscoord aHeight,
FlushDelayedResize(false); FlushDelayedResize(false);
} }
mDelayedResize.SizeTo(NSCOORD_NONE, NSCOORD_NONE); mDelayedResize.SizeTo(NSCOORD_NONE, NSCOORD_NONE);
DoSetWindowDimensions(aWidth, aHeight); DoSetWindowDimensions(aWidth, aHeight, /* aDoReflow = */ true);
} else { } else {
mDelayedResize.SizeTo(aWidth, aHeight); mDelayedResize.SizeTo(aWidth, aHeight);
if (mPresShell) { if (mPresShell) {
@ -226,15 +232,8 @@ void nsViewManager::SetWindowDimensions(nscoord aWidth, nscoord aHeight,
void nsViewManager::FlushDelayedResize(bool aDoReflow) { void nsViewManager::FlushDelayedResize(bool aDoReflow) {
if (mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE)) { if (mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE)) {
if (aDoReflow) { DoSetWindowDimensions(mDelayedResize.width, mDelayedResize.height, aDoReflow);
DoSetWindowDimensions(mDelayedResize.width, mDelayedResize.height); mDelayedResize.SizeTo(NSCOORD_NONE, NSCOORD_NONE);
mDelayedResize.SizeTo(NSCOORD_NONE, NSCOORD_NONE);
} else if (mPresShell && !mPresShell->GetIsViewportOverridden()) {
nsPresContext* presContext = mPresShell->GetPresContext();
if (presContext) {
presContext->SetVisibleArea(nsRect(nsPoint(0, 0), mDelayedResize));
}
}
} }
} }

Просмотреть файл

@ -364,7 +364,7 @@ class nsViewManager final {
LayoutDeviceIntRect ViewToWidget(nsView* aView, const nsRect& aRect) const; LayoutDeviceIntRect ViewToWidget(nsView* aView, const nsRect& aRect) const;
MOZ_CAN_RUN_SCRIPT_BOUNDARY MOZ_CAN_RUN_SCRIPT_BOUNDARY
void DoSetWindowDimensions(nscoord aWidth, nscoord aHeight); void DoSetWindowDimensions(nscoord aWidth, nscoord aHeight, bool aDoReflow);
bool ShouldDelayResize() const; bool ShouldDelayResize() const;
bool IsPainting() const { return RootViewManager()->mPainting; } bool IsPainting() const { return RootViewManager()->mPainting; }