summaryrefslogtreecommitdiffstats
path: root/gfx/layers/apz/test/gtest/TestWRScrollData.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/layers/apz/test/gtest/TestWRScrollData.cpp')
-rw-r--r--gfx/layers/apz/test/gtest/TestWRScrollData.cpp273
1 files changed, 273 insertions, 0 deletions
diff --git a/gfx/layers/apz/test/gtest/TestWRScrollData.cpp b/gfx/layers/apz/test/gtest/TestWRScrollData.cpp
new file mode 100644
index 0000000000..e267e58e90
--- /dev/null
+++ b/gfx/layers/apz/test/gtest/TestWRScrollData.cpp
@@ -0,0 +1,273 @@
+/* -*- 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 "TestWRScrollData.h"
+#include "APZTestAccess.h"
+#include "gtest/gtest.h"
+#include "FrameMetrics.h"
+#include "gfxPlatform.h"
+#include "mozilla/layers/APZUpdater.h"
+#include "mozilla/layers/LayersTypes.h"
+#include "mozilla/layers/ScrollableLayerGuid.h"
+#include "mozilla/layers/WebRenderScrollDataWrapper.h"
+#include "mozilla/UniquePtr.h"
+#include "apz/src/APZCTreeManager.h"
+
+using mozilla::layers::APZCTreeManager;
+using mozilla::layers::APZUpdater;
+using mozilla::layers::LayersId;
+using mozilla::layers::ScrollableLayerGuid;
+using mozilla::layers::ScrollMetadata;
+using mozilla::layers::TestWRScrollData;
+using mozilla::layers::WebRenderLayerScrollData;
+using mozilla::layers::WebRenderScrollDataWrapper;
+
+/* static */
+TestWRScrollData TestWRScrollData::Create(const char* aTreeShape,
+ const APZUpdater& aUpdater,
+ const LayerIntRegion* aVisibleRegions,
+ const gfx::Matrix4x4* aTransforms) {
+ // The WebRenderLayerScrollData tree needs to be created in a fairly
+ // particular way (for example, each node needs to know the number of
+ // descendants it has), so this function takes care to create the nodes
+ // in the same order as WebRenderCommandBuilder would.
+ TestWRScrollData result;
+ const size_t len = strlen(aTreeShape);
+ // "Layer index" in this function refers to the index by which a layer will
+ // be accessible via TestWRScrollData::GetLayer(), and matches the order
+ // in which the layer appears in |aTreeShape|.
+ size_t currentLayerIndex = 0;
+ struct LayerEntry {
+ size_t mLayerIndex;
+ int32_t mDescendantCount = 0;
+ };
+ // Layers we have encountered in |aTreeShape|, but have not built a
+ // WebRenderLayerScrollData for. (It can only be built after its
+ // descendants have been encountered and counted.)
+ std::stack<LayerEntry> pendingLayers;
+ std::vector<WebRenderLayerScrollData> finishedLayers;
+ // Tracks the level of nesting of '(' characters. Starts at 1 to account
+ // for the root layer.
+ size_t depth = 1;
+ // Helper function for finishing a layer once all its descendants have been
+ // encountered.
+ auto finishLayer = [&] {
+ MOZ_ASSERT(!pendingLayers.empty());
+ LayerEntry entry = pendingLayers.top();
+
+ WebRenderLayerScrollData layer;
+ APZTestAccess::InitializeForTest(layer, entry.mDescendantCount);
+ if (aVisibleRegions) {
+ layer.SetVisibleRegion(aVisibleRegions[entry.mLayerIndex]);
+ }
+ if (aTransforms) {
+ layer.SetTransform(aTransforms[entry.mLayerIndex]);
+ }
+ finishedLayers.push_back(std::move(layer));
+
+ // |finishedLayers| stores the layers in a different order than they
+ // appeared in |aTreeShape|. To be able to access layers by their layer
+ // index, keep a mapping from layer index to index in |finishedLayers|.
+ result.mIndexMap.emplace(entry.mLayerIndex, finishedLayers.size() - 1);
+
+ pendingLayers.pop();
+
+ // Keep track of descendant counts. The +1 is for the layer just finished.
+ if (!pendingLayers.empty()) {
+ pendingLayers.top().mDescendantCount += (entry.mDescendantCount + 1);
+ }
+ };
+ for (size_t i = 0; i < len; ++i) {
+ if (aTreeShape[i] == '(') {
+ ++depth;
+ } else if (aTreeShape[i] == ')') {
+ if (pendingLayers.size() <= 1) {
+ printf("Invalid tree shape: too many ')'\n");
+ MOZ_CRASH();
+ }
+ finishLayer(); // finish last layer at current depth
+ --depth;
+ } else {
+ if (aTreeShape[i] != 'x') {
+ printf("The only allowed character to represent a layer is 'x'\n");
+ MOZ_CRASH();
+ }
+ if (depth == pendingLayers.size()) {
+ // We have a previous layer at this same depth to finish.
+ if (depth <= 1) {
+ printf("The tree is only allowed to have one root\n");
+ MOZ_CRASH();
+ }
+ finishLayer();
+ }
+ MOZ_ASSERT(depth == pendingLayers.size() + 1);
+ pendingLayers.push({currentLayerIndex});
+ ++currentLayerIndex;
+ }
+ }
+ if (pendingLayers.size() != 1) {
+ printf("Invalid tree shape: '(' and ')' not balanced\n");
+ MOZ_CRASH();
+ }
+ finishLayer(); // finish root layer
+
+ // As in WebRenderCommandBuilder, the layers need to be added to the
+ // WebRenderScrollData in reverse of the order in which they were built.
+ for (auto it = finishedLayers.rbegin(); it != finishedLayers.rend(); ++it) {
+ result.AddLayerData(std::move(*it));
+ }
+ // mIndexMap also needs to be adjusted to accout for the reversal above.
+ for (auto& [layerIndex, storedIndex] : result.mIndexMap) {
+ (void)layerIndex; // suppress -Werror=unused-variable
+ storedIndex = result.GetLayerCount() - storedIndex - 1;
+ }
+
+ return result;
+}
+
+const WebRenderLayerScrollData* TestWRScrollData::operator[](
+ size_t aLayerIndex) const {
+ auto it = mIndexMap.find(aLayerIndex);
+ if (it == mIndexMap.end()) {
+ return nullptr;
+ }
+ return GetLayerData(it->second);
+}
+
+WebRenderLayerScrollData* TestWRScrollData::operator[](size_t aLayerIndex) {
+ auto it = mIndexMap.find(aLayerIndex);
+ if (it == mIndexMap.end()) {
+ return nullptr;
+ }
+ return GetLayerData(it->second);
+}
+
+void TestWRScrollData::SetScrollMetadata(
+ size_t aLayerIndex, const nsTArray<ScrollMetadata>& aMetadata) {
+ WebRenderLayerScrollData* layer = operator[](aLayerIndex);
+ MOZ_ASSERT(layer);
+ for (const ScrollMetadata& metadata : aMetadata) {
+ layer->AppendScrollMetadata(*this, metadata);
+ }
+}
+
+class WebRenderScrollDataWrapperTester : public ::testing::Test {
+ protected:
+ virtual void SetUp() {
+ // This ensures ScrollMetadata::sNullMetadata is initialized.
+ gfxPlatform::GetPlatform();
+
+ mManager = new APZCTreeManager(LayersId{0});
+ mUpdater = new APZUpdater(mManager, false);
+ }
+
+ RefPtr<APZCTreeManager> mManager;
+ RefPtr<APZUpdater> mUpdater;
+};
+
+TEST_F(WebRenderScrollDataWrapperTester, SimpleTree) {
+ auto layers = TestWRScrollData::Create("x(x(x(xx)x(x)))", *mUpdater);
+ WebRenderScrollDataWrapper w0(*mUpdater, &layers);
+
+ ASSERT_EQ(layers[0], w0.GetLayer());
+ WebRenderScrollDataWrapper w1 = w0.GetLastChild();
+ ASSERT_EQ(layers[1], w1.GetLayer());
+ ASSERT_FALSE(w1.GetPrevSibling().IsValid());
+ WebRenderScrollDataWrapper w5 = w1.GetLastChild();
+ ASSERT_EQ(layers[5], w5.GetLayer());
+ WebRenderScrollDataWrapper w6 = w5.GetLastChild();
+ ASSERT_EQ(layers[6], w6.GetLayer());
+ ASSERT_FALSE(w6.GetLastChild().IsValid());
+ WebRenderScrollDataWrapper w2 = w5.GetPrevSibling();
+ ASSERT_EQ(layers[2], w2.GetLayer());
+ ASSERT_FALSE(w2.GetPrevSibling().IsValid());
+ WebRenderScrollDataWrapper w4 = w2.GetLastChild();
+ ASSERT_EQ(layers[4], w4.GetLayer());
+ ASSERT_FALSE(w4.GetLastChild().IsValid());
+ WebRenderScrollDataWrapper w3 = w4.GetPrevSibling();
+ ASSERT_EQ(layers[3], w3.GetLayer());
+ ASSERT_FALSE(w3.GetLastChild().IsValid());
+ ASSERT_FALSE(w3.GetPrevSibling().IsValid());
+}
+
+static ScrollMetadata MakeMetadata(ScrollableLayerGuid::ViewID aId) {
+ ScrollMetadata metadata;
+ metadata.GetMetrics().SetScrollId(aId);
+ return metadata;
+}
+
+TEST_F(WebRenderScrollDataWrapperTester, MultiFramemetricsTree) {
+ auto layers = TestWRScrollData::Create("x(x(x(xx)x(x)))", *mUpdater);
+
+ nsTArray<ScrollMetadata> metadata;
+ metadata.InsertElementAt(0,
+ MakeMetadata(ScrollableLayerGuid::START_SCROLL_ID +
+ 0)); // topmost of root layer
+ metadata.InsertElementAt(0,
+ MakeMetadata(ScrollableLayerGuid::NULL_SCROLL_ID));
+ metadata.InsertElementAt(
+ 0, MakeMetadata(ScrollableLayerGuid::START_SCROLL_ID + 1));
+ metadata.InsertElementAt(
+ 0, MakeMetadata(ScrollableLayerGuid::START_SCROLL_ID + 2));
+ metadata.InsertElementAt(0,
+ MakeMetadata(ScrollableLayerGuid::NULL_SCROLL_ID));
+ metadata.InsertElementAt(
+ 0, MakeMetadata(
+ ScrollableLayerGuid::NULL_SCROLL_ID)); // bottom of root layer
+ layers.SetScrollMetadata(0, metadata);
+
+ metadata.Clear();
+ metadata.InsertElementAt(
+ 0, MakeMetadata(ScrollableLayerGuid::START_SCROLL_ID + 3));
+ layers.SetScrollMetadata(1, metadata);
+
+ metadata.Clear();
+ metadata.InsertElementAt(
+ 0, MakeMetadata(ScrollableLayerGuid::START_SCROLL_ID + 4));
+ layers.SetScrollMetadata(2, metadata);
+
+ metadata.Clear();
+ metadata.InsertElementAt(
+ 0, MakeMetadata(ScrollableLayerGuid::START_SCROLL_ID + 5));
+ layers.SetScrollMetadata(4, metadata);
+
+ metadata.Clear();
+ metadata.InsertElementAt(0,
+ MakeMetadata(ScrollableLayerGuid::NULL_SCROLL_ID));
+ metadata.InsertElementAt(
+ 0, MakeMetadata(ScrollableLayerGuid::START_SCROLL_ID + 6));
+ layers.SetScrollMetadata(5, metadata);
+
+ WebRenderScrollDataWrapper wrapper(*mUpdater, &layers);
+ nsTArray<WebRenderLayerScrollData*> expectedLayers;
+ expectedLayers.AppendElement(layers[0]);
+ expectedLayers.AppendElement(layers[0]);
+ expectedLayers.AppendElement(layers[0]);
+ expectedLayers.AppendElement(layers[0]);
+ expectedLayers.AppendElement(layers[0]);
+ expectedLayers.AppendElement(layers[0]);
+ expectedLayers.AppendElement(layers[1]);
+ expectedLayers.AppendElement(layers[5]);
+ expectedLayers.AppendElement(layers[5]);
+ expectedLayers.AppendElement(layers[6]);
+ nsTArray<ScrollableLayerGuid::ViewID> expectedIds;
+ expectedIds.AppendElement(ScrollableLayerGuid::START_SCROLL_ID + 0);
+ expectedIds.AppendElement(ScrollableLayerGuid::NULL_SCROLL_ID);
+ expectedIds.AppendElement(ScrollableLayerGuid::START_SCROLL_ID + 1);
+ expectedIds.AppendElement(ScrollableLayerGuid::START_SCROLL_ID + 2);
+ expectedIds.AppendElement(ScrollableLayerGuid::NULL_SCROLL_ID);
+ expectedIds.AppendElement(ScrollableLayerGuid::NULL_SCROLL_ID);
+ expectedIds.AppendElement(ScrollableLayerGuid::START_SCROLL_ID + 3);
+ expectedIds.AppendElement(ScrollableLayerGuid::NULL_SCROLL_ID);
+ expectedIds.AppendElement(ScrollableLayerGuid::START_SCROLL_ID + 6);
+ expectedIds.AppendElement(ScrollableLayerGuid::NULL_SCROLL_ID);
+ for (int i = 0; i < 10; i++) {
+ ASSERT_EQ(expectedLayers[i], wrapper.GetLayer());
+ ASSERT_EQ(expectedIds[i], wrapper.Metrics().GetScrollId());
+ wrapper = wrapper.GetLastChild();
+ }
+ ASSERT_FALSE(wrapper.IsValid());
+}