summaryrefslogtreecommitdiffstats
path: root/gfx/layers/apz/test/gtest/mvm/TestMobileViewportManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/layers/apz/test/gtest/mvm/TestMobileViewportManager.cpp')
-rw-r--r--gfx/layers/apz/test/gtest/mvm/TestMobileViewportManager.cpp220
1 files changed, 220 insertions, 0 deletions
diff --git a/gfx/layers/apz/test/gtest/mvm/TestMobileViewportManager.cpp b/gfx/layers/apz/test/gtest/mvm/TestMobileViewportManager.cpp
new file mode 100644
index 0000000000..cd7e0a7d0d
--- /dev/null
+++ b/gfx/layers/apz/test/gtest/mvm/TestMobileViewportManager.cpp
@@ -0,0 +1,220 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+#include "gmock/gmock.h"
+
+#include <functional>
+
+#include "MobileViewportManager.h"
+#include "mozilla/MVMContext.h"
+#include "mozilla/dom/Event.h"
+
+using namespace mozilla;
+
+class MockMVMContext : public MVMContext {
+ using AutoSizeFlag = nsViewportInfo::AutoSizeFlag;
+ using AutoScaleFlag = nsViewportInfo::AutoScaleFlag;
+ using ZoomFlag = nsViewportInfo::ZoomFlag;
+
+ // A "layout function" is a function that computes the content size
+ // as a function of the ICB size.
+ using LayoutFunction = std::function<CSSSize(CSSSize aICBSize)>;
+
+ public:
+ // MVMContext methods we don't care to implement.
+ MOCK_METHOD3(AddEventListener,
+ void(const nsAString& aType, nsIDOMEventListener* aListener,
+ bool aUseCapture));
+ MOCK_METHOD3(RemoveEventListener,
+ void(const nsAString& aType, nsIDOMEventListener* aListener,
+ bool aUseCapture));
+ MOCK_METHOD3(AddObserver, void(nsIObserver* aObserver, const char* aTopic,
+ bool aOwnsWeak));
+ MOCK_METHOD2(RemoveObserver,
+ void(nsIObserver* aObserver, const char* aTopic));
+ MOCK_METHOD0(Destroy, void());
+
+ MOCK_METHOD1(SetVisualViewportSize, void(const CSSSize& aSize));
+ MOCK_METHOD0(PostVisualViewportResizeEventByDynamicToolbar, void());
+ MOCK_METHOD0(UpdateDisplayPortMargins, void());
+
+ void SetMVM(MobileViewportManager* aMVM) { mMVM = aMVM; }
+
+ // MVMContext method implementations.
+ nsViewportInfo GetViewportInfo(const ScreenIntSize& aDisplaySize) const {
+ // This is a very basic approximation of what Document::GetViewportInfo()
+ // does in the most common cases.
+ // Ideally, we would invoke the algorithm in Document::GetViewportInfo()
+ // itself, but that would require refactoring it a bit to remove
+ // dependencies on the actual Document which we don't have available in
+ // this test harness.
+ CSSSize viewportSize = mDisplaySize / mDeviceScale;
+ if (mAutoSizeFlag == AutoSizeFlag::FixedSize) {
+ viewportSize = CSSSize(mFixedViewportWidth,
+ mFixedViewportWidth * (float(mDisplaySize.height) /
+ mDisplaySize.width));
+ }
+ return nsViewportInfo(mDefaultScale, mMinScale, mMaxScale, viewportSize,
+ mAutoSizeFlag, mAutoScaleFlag, mZoomFlag,
+ dom::ViewportFitType::Auto);
+ }
+ CSSToLayoutDeviceScale CSSToDevPixelScale() const { return mDeviceScale; }
+ float GetResolution() const { return mResolution; }
+ bool SubjectMatchesDocument(nsISupports* aSubject) const { return true; }
+ Maybe<CSSRect> CalculateScrollableRectForRSF() const {
+ return Some(CSSRect(CSSPoint(), mContentSize));
+ }
+ bool IsResolutionUpdatedByApz() const { return false; }
+ LayoutDeviceMargin ScrollbarAreaToExcludeFromCompositionBounds() const {
+ return LayoutDeviceMargin();
+ }
+ Maybe<LayoutDeviceIntSize> GetContentViewerSize() const {
+ return Some(mDisplaySize);
+ }
+ bool AllowZoomingForDocument() const { return true; }
+ bool IsInReaderMode() const { return false; }
+ bool IsDocumentLoading() const { return false; }
+
+ void SetResolutionAndScaleTo(float aResolution,
+ ResolutionChangeOrigin aOrigin) {
+ mResolution = aResolution;
+ mMVM->ResolutionUpdated(aOrigin);
+ }
+ void Reflow(const CSSSize& aNewSize) {
+ mICBSize = aNewSize;
+ mContentSize = mLayoutFunction(mICBSize);
+ }
+
+ // Allow test code to modify the input metrics.
+ void SetMinScale(CSSToScreenScale aMinScale) { mMinScale = aMinScale; }
+ void SetMaxScale(CSSToScreenScale aMaxScale) { mMaxScale = aMaxScale; }
+ void SetInitialScale(CSSToScreenScale aInitialScale) {
+ mDefaultScale = aInitialScale;
+ mAutoScaleFlag = AutoScaleFlag::FixedScale;
+ }
+ void SetFixedViewportWidth(CSSCoord aWidth) {
+ mFixedViewportWidth = aWidth;
+ mAutoSizeFlag = AutoSizeFlag::FixedSize;
+ }
+ void SetDisplaySize(const LayoutDeviceIntSize& aNewDisplaySize) {
+ mDisplaySize = aNewDisplaySize;
+ }
+ void SetLayoutFunction(const LayoutFunction& aLayoutFunction) {
+ mLayoutFunction = aLayoutFunction;
+ }
+
+ // Allow test code to query the output metrics.
+ CSSSize GetICBSize() const { return mICBSize; }
+ CSSSize GetContentSize() const { return mContentSize; }
+
+ private:
+ // Input metrics, with some sensible defaults.
+ LayoutDeviceIntSize mDisplaySize{300, 600};
+ CSSToScreenScale mDefaultScale{1.0f};
+ CSSToScreenScale mMinScale{0.25f};
+ CSSToScreenScale mMaxScale{10.0f};
+ CSSToLayoutDeviceScale mDeviceScale{1.0f};
+ CSSCoord mFixedViewportWidth;
+ AutoSizeFlag mAutoSizeFlag = AutoSizeFlag::AutoSize;
+ AutoScaleFlag mAutoScaleFlag = AutoScaleFlag::AutoScale;
+ ZoomFlag mZoomFlag = ZoomFlag::AllowZoom;
+ // As a default layout function, just set the content size to the ICB size.
+ LayoutFunction mLayoutFunction = [](CSSSize aICBSize) { return aICBSize; };
+
+ // Output metrics.
+ float mResolution = 1.0f;
+ CSSSize mICBSize;
+ CSSSize mContentSize;
+
+ MobileViewportManager* mMVM = nullptr;
+};
+
+class MVMTester : public ::testing::Test {
+ public:
+ MVMTester()
+ : mMVMContext(new MockMVMContext()),
+ mMVM(new MobileViewportManager(
+ mMVMContext,
+ MobileViewportManager::ManagerType::VisualAndMetaViewport)) {
+ mMVMContext->SetMVM(mMVM.get());
+ }
+
+ void Resize(const LayoutDeviceIntSize& aNewDisplaySize) {
+ mMVMContext->SetDisplaySize(aNewDisplaySize);
+ mMVM->RequestReflow(false);
+ }
+
+ protected:
+ RefPtr<MockMVMContext> mMVMContext;
+ RefPtr<MobileViewportManager> mMVM;
+};
+
+TEST_F(MVMTester, ZoomBoundsRespectedAfterRotation_Bug1536755) {
+ // Set up initial conditions.
+ mMVMContext->SetDisplaySize(LayoutDeviceIntSize(600, 300));
+ mMVMContext->SetInitialScale(CSSToScreenScale(1.0f));
+ mMVMContext->SetMinScale(CSSToScreenScale(1.0f));
+ mMVMContext->SetMaxScale(CSSToScreenScale(1.0f));
+ // Set a layout function that simulates a page which is twice
+ // as tall as it is wide.
+ mMVMContext->SetLayoutFunction([](CSSSize aICBSize) {
+ return CSSSize(aICBSize.width, aICBSize.width * 2);
+ });
+
+ // Perform an initial viewport computation and reflow, and
+ // sanity-check the results.
+ mMVM->SetInitialViewport();
+ EXPECT_EQ(CSSSize(600, 300), mMVMContext->GetICBSize());
+ EXPECT_EQ(CSSSize(600, 1200), mMVMContext->GetContentSize());
+ EXPECT_EQ(1.0f, mMVMContext->GetResolution());
+
+ // Now rotate the screen, and check that the minimum and maximum
+ // scales are still respected after the rotation.
+ Resize(LayoutDeviceIntSize(300, 600));
+ EXPECT_EQ(CSSSize(300, 600), mMVMContext->GetICBSize());
+ EXPECT_EQ(CSSSize(300, 600), mMVMContext->GetContentSize());
+ EXPECT_EQ(1.0f, mMVMContext->GetResolution());
+}
+
+TEST_F(MVMTester, LandscapeToPortraitRotation_Bug1523844) {
+ // Set up initial conditions.
+ mMVMContext->SetDisplaySize(LayoutDeviceIntSize(300, 600));
+ // Set a layout function that simulates a page with a fixed
+ // content size that's as wide as the screen in one orientation
+ // (and wider in the other).
+ mMVMContext->SetLayoutFunction(
+ [](CSSSize aICBSize) { return CSSSize(600, 1200); });
+
+ // Simulate a "DOMMetaAdded" event being fired before calling
+ // SetInitialViewport(). This matches what typically happens
+ // during real usage (the MVM receives the "DOMMetaAdded"
+ // before the "load", and it's the "load" that calls
+ // SetInitialViewport()), and is important to trigger this
+ // bug, because it causes the MVM to be stuck with an
+ // "mRestoreResolution" (prior to the fix).
+ mMVM->HandleDOMMetaAdded();
+
+ // Perform an initial viewport computation and reflow, and
+ // sanity-check the results.
+ mMVM->SetInitialViewport();
+ EXPECT_EQ(CSSSize(300, 600), mMVMContext->GetICBSize());
+ EXPECT_EQ(CSSSize(600, 1200), mMVMContext->GetContentSize());
+ EXPECT_EQ(0.5f, mMVMContext->GetResolution());
+
+ // Rotate to landscape.
+ Resize(LayoutDeviceIntSize(600, 300));
+ EXPECT_EQ(CSSSize(600, 300), mMVMContext->GetICBSize());
+ EXPECT_EQ(CSSSize(600, 1200), mMVMContext->GetContentSize());
+ EXPECT_EQ(1.0f, mMVMContext->GetResolution());
+
+ // Rotate back to portrait and check that we have returned
+ // to the portrait resolution.
+ Resize(LayoutDeviceIntSize(300, 600));
+ EXPECT_EQ(CSSSize(300, 600), mMVMContext->GetICBSize());
+ EXPECT_EQ(CSSSize(600, 1200), mMVMContext->GetContentSize());
+ EXPECT_EQ(0.5f, mMVMContext->GetResolution());
+}