Bug 1644271 - Add a ManagerType field to the MVM, to allow conditional behaviour. r=tnikkel

The MVM is needed for both handling of meta-viewport tags and APZ zooming.
However, the set of functionality needed in the two modes are not the same.
This patch adds a mechanism to create an MVM with a flag that lets it know
which mode it is operating in. Eventually we may want to split this into two
or more classes but for now this seems like a reasonable way forward.

The flag is currently set on the MVM on creation based on whether or not the
meta-viewport support is needed. There's no code that meaningfully *uses* the
flag yet, so this patch should have no functional change. The bulk of the
patch is ensuring that we appropriately destroy and re-create the MVM if the
flag required changes.

Differential Revision: https://phabricator.services.mozilla.com/D79224
This commit is contained in:
Kartikaya Gupta
2020-06-12 01:15:42 +00:00
parent cd6fb9fded
commit 3969b349de
4 changed files with 78 additions and 45 deletions

View File

@@ -137,7 +137,9 @@ class MVMTester : public ::testing::Test {
public:
MVMTester()
: mMVMContext(new MockMVMContext()),
mMVM(new MobileViewportManager(mMVMContext)) {
mMVM(new MobileViewportManager(
mMVMContext,
MobileViewportManager::ManagerType::VisualAndMetaViewport)) {
mMVMContext->SetMVM(mMVM.get());
}

View File

@@ -31,8 +31,12 @@ using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::layers;
MobileViewportManager::MobileViewportManager(MVMContext* aContext)
: mContext(aContext), mIsFirstPaint(false), mPainted(false) {
MobileViewportManager::MobileViewportManager(MVMContext* aContext,
ManagerType aType)
: mContext(aContext),
mManagerType(aType),
mIsFirstPaint(false),
mPainted(false) {
MOZ_ASSERT(mContext);
MVM_LOG("%p: creating with context %p\n", this, mContext.get());

View File

@@ -31,9 +31,20 @@ class MobileViewportManager final : public nsIDOMEventListener,
NS_DECL_NSIDOMEVENTLISTENER
NS_DECL_NSIOBSERVER
explicit MobileViewportManager(mozilla::MVMContext* aContext);
/* The MobileViewportManager might be required to handle meta-viewport tags
* and changes, or it might not (e.g. if we are in a desktop-zooming setup).
* This enum indicates which mode the manager is in. It might make sense to
* split these two "modes" into two separate classes but for now they have a
* bunch of shared code and it's uncertain if that shared set will expand or
* contract. */
enum class ManagerType { VisualAndMetaViewport, VisualViewportOnly };
explicit MobileViewportManager(mozilla::MVMContext* aContext,
ManagerType aType);
void Destroy();
ManagerType GetManagerType() { return mManagerType; }
/* Provide a resolution to use during the first paint instead of the default
* resolution computed from the viewport info metadata. This is in the same
* "units" as the argument to nsDOMWindowUtils::SetResolutionAndScaleTo.
@@ -162,6 +173,7 @@ class MobileViewportManager final : public nsIDOMEventListener,
mozilla::CSSToScreenScale GetZoom() const;
RefPtr<mozilla::MVMContext> mContext;
ManagerType mManagerType;
bool mIsFirstPaint;
bool mPainted;
mozilla::LayoutDeviceIntSize mDisplaySize;

View File

@@ -10868,74 +10868,89 @@ RefPtr<MobileViewportManager> PresShell::GetMobileViewportManager() const {
return mMobileViewportManager;
}
bool UseMobileViewportManager(PresShell* aPresShell, Document* aDocument) {
Maybe<MobileViewportManager::ManagerType> UseMobileViewportManager(
PresShell* aPresShell, Document* aDocument) {
// If we're not using APZ, we won't be able to zoom, so there is no
// point in having an MVM.
if (nsPresContext* presContext = aPresShell->GetPresContext()) {
if (nsIWidget* widget = presContext->GetNearestWidget()) {
if (!widget->AsyncPanZoomEnabled()) {
return false;
return Nothing();
}
}
}
return StaticPrefs::apz_mvm_force_enabled() ||
nsLayoutUtils::ShouldHandleMetaViewport(aDocument) ||
nsLayoutUtils::AllowZoomingForDocument(aDocument);
if (nsLayoutUtils::ShouldHandleMetaViewport(aDocument)) {
return Some(MobileViewportManager::ManagerType::VisualAndMetaViewport);
}
if (StaticPrefs::apz_mvm_force_enabled() ||
nsLayoutUtils::AllowZoomingForDocument(aDocument)) {
return Some(MobileViewportManager::ManagerType::VisualViewportOnly);
}
return Nothing();
}
void PresShell::UpdateViewportOverridden(bool aAfterInitialization) {
// Determine if we require a MobileViewportManager. We need one any
// time we allow resolution zooming for a document, and any time we
// want to obey <meta name="viewport"> tags for it.
bool needMVM = UseMobileViewportManager(this, mDocument);
// Determine if we require a MobileViewportManager, and what kind if so. We
// need one any time we allow resolution zooming for a document, and any time
// we want to obey <meta name="viewport"> tags for it.
Maybe<MobileViewportManager::ManagerType> mvmType =
UseMobileViewportManager(this, mDocument);
if (needMVM == !!mMobileViewportManager) {
// Either we've need one and we've already got it, or we don't need one
// and don't have it. Either way, we're done.
if (mvmType.isNothing() && !mMobileViewportManager) {
// We don't need one and don't have it. So we're done.
return;
}
if (mvmType && mMobileViewportManager &&
*mvmType == mMobileViewportManager->GetManagerType()) {
// We need one and we have one of the correct type, so we're done.
}
if (mMobileViewportManager) {
// We have one, but we need to either destroy it completely to replace it
// with another one of the correct type. So either way, let's destroy the
// one we have.
mMobileViewportManager->Destroy();
mMobileViewportManager = nullptr;
mMVMContext = nullptr;
ResetVisualViewportSize();
// After we clear out the MVM and the MVMContext, also reset the
// resolution to its pre-MVM value.
SetResolutionAndScaleTo(mDocument->GetSavedResolutionBeforeMVM(),
ResolutionChangeOrigin::MainThreadRestore);
if (aAfterInitialization) {
// Force a reflow to our correct size by going back to the docShell
// and asking it to reassert its size. This is necessary because
// everything underneath the docShell, like the ViewManager, has been
// altered by the MobileViewportManager in an irreversible way.
nsDocShell* docShell =
static_cast<nsDocShell*>(GetPresContext()->GetDocShell());
int32_t width, height;
docShell->GetSize(&width, &height);
docShell->SetSize(width, height, false);
}
}
if (mvmType) {
// Let's create the MVM of the type that we need. At this point we shouldn't
// have one.
MOZ_ASSERT(!mMobileViewportManager);
if (needMVM) {
if (mPresContext->IsRootContentDocumentCrossProcess()) {
// Store the resolution so we can restore to this resolution when
// the MVM is destroyed.
mDocument->SetSavedResolutionBeforeMVM(mResolution.valueOr(1.0f));
mMVMContext = new GeckoMVMContext(mDocument, this);
mMobileViewportManager = new MobileViewportManager(mMVMContext);
mMobileViewportManager = new MobileViewportManager(mMVMContext, *mvmType);
if (aAfterInitialization) {
// Setting the initial viewport will trigger a reflow.
mMobileViewportManager->SetInitialViewport();
}
}
return;
}
MOZ_ASSERT(mMobileViewportManager,
"Shouldn't reach this without a MobileViewportManager.");
mMobileViewportManager->Destroy();
mMobileViewportManager = nullptr;
mMVMContext = nullptr;
ResetVisualViewportSize();
// After we clear out the MVM and the MVMContext, also reset the
// resolution to its pre-MVM value.
SetResolutionAndScaleTo(mDocument->GetSavedResolutionBeforeMVM(),
ResolutionChangeOrigin::MainThreadRestore);
if (aAfterInitialization) {
// Force a reflow to our correct size by going back to the docShell
// and asking it to reassert its size. This is necessary because
// everything underneath the docShell, like the ViewManager, has been
// altered by the MobileViewportManager in an irreversible way.
nsDocShell* docShell =
static_cast<nsDocShell*>(GetPresContext()->GetDocShell());
int32_t width, height;
docShell->GetSize(&width, &height);
docShell->SetSize(width, height, false);
}
}