TestWRScrollData.cpp (10548B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "TestWRScrollData.h" 8 #include "APZTestAccess.h" 9 #include "gtest/gtest.h" 10 #include "FrameMetrics.h" 11 #include "gfxPlatform.h" 12 #include "mozilla/layers/APZUpdater.h" 13 #include "mozilla/layers/LayersTypes.h" 14 #include "mozilla/layers/ScrollableLayerGuid.h" 15 #include "mozilla/layers/WebRenderScrollDataWrapper.h" 16 #include "apz/src/APZCTreeManager.h" 17 18 using mozilla::layers::APZCTreeManager; 19 using mozilla::layers::APZUpdater; 20 using mozilla::layers::LayersId; 21 using mozilla::layers::ScrollableLayerGuid; 22 using mozilla::layers::ScrollMetadata; 23 using mozilla::layers::TestWRScrollData; 24 using mozilla::layers::WebRenderLayerScrollData; 25 using mozilla::layers::WebRenderScrollDataWrapper; 26 27 /* static */ 28 TestWRScrollData TestWRScrollData::Create(const char* aTreeShape, 29 const APZUpdater& aUpdater, 30 const LayerIntRect* aVisibleRects, 31 const gfx::Matrix4x4* aTransforms) { 32 // The WebRenderLayerScrollData tree needs to be created in a fairly 33 // particular way (for example, each node needs to know the number of 34 // descendants it has), so this function takes care to create the nodes 35 // in the same order as WebRenderCommandBuilder would. 36 TestWRScrollData result; 37 const size_t len = strlen(aTreeShape); 38 // "Layer index" in this function refers to the index by which a layer will 39 // be accessible via TestWRScrollData::GetLayer(), and matches the order 40 // in which the layer appears in |aTreeShape|. 41 size_t currentLayerIndex = 0; 42 struct LayerEntry { 43 size_t mLayerIndex; 44 int32_t mDescendantCount = 0; 45 }; 46 // Layers we have encountered in |aTreeShape|, but have not built a 47 // WebRenderLayerScrollData for. (It can only be built after its 48 // descendants have been encountered and counted.) 49 std::stack<LayerEntry> pendingLayers; 50 std::vector<WebRenderLayerScrollData> finishedLayers; 51 // Tracks the level of nesting of '(' characters. Starts at 1 to account 52 // for the root layer. 53 size_t depth = 1; 54 // Helper function for finishing a layer once all its descendants have been 55 // encountered. 56 auto finishLayer = [&] { 57 MOZ_ASSERT(!pendingLayers.empty()); 58 LayerEntry entry = pendingLayers.top(); 59 60 WebRenderLayerScrollData layer; 61 APZTestAccess::InitializeForTest(layer, entry.mDescendantCount); 62 if (aVisibleRects) { 63 layer.SetVisibleRect(aVisibleRects[entry.mLayerIndex]); 64 } 65 if (aTransforms) { 66 layer.SetTransform(aTransforms[entry.mLayerIndex]); 67 } 68 finishedLayers.push_back(std::move(layer)); 69 70 // |finishedLayers| stores the layers in a different order than they 71 // appeared in |aTreeShape|. To be able to access layers by their layer 72 // index, keep a mapping from layer index to index in |finishedLayers|. 73 result.mIndexMap.emplace(entry.mLayerIndex, finishedLayers.size() - 1); 74 75 pendingLayers.pop(); 76 77 // Keep track of descendant counts. The +1 is for the layer just finished. 78 if (!pendingLayers.empty()) { 79 pendingLayers.top().mDescendantCount += (entry.mDescendantCount + 1); 80 } 81 }; 82 for (size_t i = 0; i < len; ++i) { 83 if (aTreeShape[i] == '(') { 84 ++depth; 85 } else if (aTreeShape[i] == ')') { 86 if (pendingLayers.size() <= 1) { 87 printf("Invalid tree shape: too many ')'\n"); 88 MOZ_CRASH(); 89 } 90 finishLayer(); // finish last layer at current depth 91 --depth; 92 } else { 93 if (aTreeShape[i] != 'x') { 94 printf("The only allowed character to represent a layer is 'x'\n"); 95 MOZ_CRASH(); 96 } 97 if (depth == pendingLayers.size()) { 98 // We have a previous layer at this same depth to finish. 99 if (depth <= 1) { 100 printf("The tree is only allowed to have one root\n"); 101 MOZ_CRASH(); 102 } 103 finishLayer(); 104 } 105 MOZ_ASSERT(depth == pendingLayers.size() + 1); 106 pendingLayers.push({currentLayerIndex}); 107 ++currentLayerIndex; 108 } 109 } 110 if (pendingLayers.size() != 1) { 111 printf("Invalid tree shape: '(' and ')' not balanced\n"); 112 MOZ_CRASH(); 113 } 114 finishLayer(); // finish root layer 115 116 // As in WebRenderCommandBuilder, the layers need to be added to the 117 // WebRenderScrollData in reverse of the order in which they were built. 118 for (auto it = finishedLayers.rbegin(); it != finishedLayers.rend(); ++it) { 119 result.AddLayerData(std::move(*it)); 120 } 121 // mIndexMap also needs to be adjusted to accout for the reversal above. 122 for (auto& [layerIndex, storedIndex] : result.mIndexMap) { 123 (void)layerIndex; // suppress -Werror=unused-variable 124 storedIndex = result.GetLayerCount() - storedIndex - 1; 125 } 126 127 return result; 128 } 129 130 const WebRenderLayerScrollData* TestWRScrollData::operator[]( 131 size_t aLayerIndex) const { 132 auto it = mIndexMap.find(aLayerIndex); 133 if (it == mIndexMap.end()) { 134 return nullptr; 135 } 136 return GetLayerData(it->second); 137 } 138 139 WebRenderLayerScrollData* TestWRScrollData::operator[](size_t aLayerIndex) { 140 auto it = mIndexMap.find(aLayerIndex); 141 if (it == mIndexMap.end()) { 142 return nullptr; 143 } 144 return GetLayerData(it->second); 145 } 146 147 void TestWRScrollData::SetScrollMetadata( 148 size_t aLayerIndex, const nsTArray<ScrollMetadata>& aMetadata) { 149 WebRenderLayerScrollData* layer = operator[](aLayerIndex); 150 MOZ_ASSERT(layer); 151 for (const ScrollMetadata& metadata : aMetadata) { 152 layer->AppendScrollMetadata(*this, metadata); 153 } 154 } 155 156 class WebRenderScrollDataWrapperTester : public ::testing::Test { 157 protected: 158 virtual void SetUp() { 159 // This ensures ScrollMetadata::sNullMetadata is initialized. 160 gfxPlatform::GetPlatform(); 161 162 mManager = APZCTreeManager::Create(LayersId{0}); 163 mUpdater = new APZUpdater(mManager, false); 164 } 165 166 RefPtr<APZCTreeManager> mManager; 167 RefPtr<APZUpdater> mUpdater; 168 }; 169 170 TEST_F(WebRenderScrollDataWrapperTester, SimpleTree) { 171 auto layers = TestWRScrollData::Create("x(x(x(xx)x(x)))", *mUpdater); 172 WebRenderScrollDataWrapper w0(*mUpdater, &layers); 173 174 ASSERT_EQ(layers[0], w0.GetLayer()); 175 WebRenderScrollDataWrapper w1 = w0.GetLastChild(); 176 ASSERT_EQ(layers[1], w1.GetLayer()); 177 ASSERT_FALSE(w1.GetPrevSibling().IsValid()); 178 WebRenderScrollDataWrapper w5 = w1.GetLastChild(); 179 ASSERT_EQ(layers[5], w5.GetLayer()); 180 WebRenderScrollDataWrapper w6 = w5.GetLastChild(); 181 ASSERT_EQ(layers[6], w6.GetLayer()); 182 ASSERT_FALSE(w6.GetLastChild().IsValid()); 183 WebRenderScrollDataWrapper w2 = w5.GetPrevSibling(); 184 ASSERT_EQ(layers[2], w2.GetLayer()); 185 ASSERT_FALSE(w2.GetPrevSibling().IsValid()); 186 WebRenderScrollDataWrapper w4 = w2.GetLastChild(); 187 ASSERT_EQ(layers[4], w4.GetLayer()); 188 ASSERT_FALSE(w4.GetLastChild().IsValid()); 189 WebRenderScrollDataWrapper w3 = w4.GetPrevSibling(); 190 ASSERT_EQ(layers[3], w3.GetLayer()); 191 ASSERT_FALSE(w3.GetLastChild().IsValid()); 192 ASSERT_FALSE(w3.GetPrevSibling().IsValid()); 193 } 194 195 static ScrollMetadata MakeMetadata(ScrollableLayerGuid::ViewID aId) { 196 ScrollMetadata metadata; 197 metadata.GetMetrics().SetScrollId(aId); 198 return metadata; 199 } 200 201 TEST_F(WebRenderScrollDataWrapperTester, MultiFramemetricsTree) { 202 auto layers = TestWRScrollData::Create("x(x(x(xx)x(x)))", *mUpdater); 203 204 nsTArray<ScrollMetadata> metadata; 205 metadata.InsertElementAt(0, 206 MakeMetadata(ScrollableLayerGuid::START_SCROLL_ID + 207 0)); // topmost of root layer 208 metadata.InsertElementAt(0, 209 MakeMetadata(ScrollableLayerGuid::NULL_SCROLL_ID)); 210 metadata.InsertElementAt( 211 0, MakeMetadata(ScrollableLayerGuid::START_SCROLL_ID + 1)); 212 metadata.InsertElementAt( 213 0, MakeMetadata(ScrollableLayerGuid::START_SCROLL_ID + 2)); 214 metadata.InsertElementAt(0, 215 MakeMetadata(ScrollableLayerGuid::NULL_SCROLL_ID)); 216 metadata.InsertElementAt( 217 0, MakeMetadata( 218 ScrollableLayerGuid::NULL_SCROLL_ID)); // bottom of root layer 219 layers.SetScrollMetadata(0, metadata); 220 221 metadata.Clear(); 222 metadata.InsertElementAt( 223 0, MakeMetadata(ScrollableLayerGuid::START_SCROLL_ID + 3)); 224 layers.SetScrollMetadata(1, metadata); 225 226 metadata.Clear(); 227 metadata.InsertElementAt( 228 0, MakeMetadata(ScrollableLayerGuid::START_SCROLL_ID + 4)); 229 layers.SetScrollMetadata(2, metadata); 230 231 metadata.Clear(); 232 metadata.InsertElementAt( 233 0, MakeMetadata(ScrollableLayerGuid::START_SCROLL_ID + 5)); 234 layers.SetScrollMetadata(4, metadata); 235 236 metadata.Clear(); 237 metadata.InsertElementAt(0, 238 MakeMetadata(ScrollableLayerGuid::NULL_SCROLL_ID)); 239 metadata.InsertElementAt( 240 0, MakeMetadata(ScrollableLayerGuid::START_SCROLL_ID + 6)); 241 layers.SetScrollMetadata(5, metadata); 242 243 WebRenderScrollDataWrapper wrapper(*mUpdater, &layers); 244 nsTArray<WebRenderLayerScrollData*> expectedLayers; 245 expectedLayers.AppendElement(layers[0]); 246 expectedLayers.AppendElement(layers[0]); 247 expectedLayers.AppendElement(layers[0]); 248 expectedLayers.AppendElement(layers[0]); 249 expectedLayers.AppendElement(layers[0]); 250 expectedLayers.AppendElement(layers[0]); 251 expectedLayers.AppendElement(layers[1]); 252 expectedLayers.AppendElement(layers[5]); 253 expectedLayers.AppendElement(layers[5]); 254 expectedLayers.AppendElement(layers[6]); 255 nsTArray<ScrollableLayerGuid::ViewID> expectedIds; 256 expectedIds.AppendElement(ScrollableLayerGuid::START_SCROLL_ID + 0); 257 expectedIds.AppendElement(ScrollableLayerGuid::NULL_SCROLL_ID); 258 expectedIds.AppendElement(ScrollableLayerGuid::START_SCROLL_ID + 1); 259 expectedIds.AppendElement(ScrollableLayerGuid::START_SCROLL_ID + 2); 260 expectedIds.AppendElement(ScrollableLayerGuid::NULL_SCROLL_ID); 261 expectedIds.AppendElement(ScrollableLayerGuid::NULL_SCROLL_ID); 262 expectedIds.AppendElement(ScrollableLayerGuid::START_SCROLL_ID + 3); 263 expectedIds.AppendElement(ScrollableLayerGuid::NULL_SCROLL_ID); 264 expectedIds.AppendElement(ScrollableLayerGuid::START_SCROLL_ID + 6); 265 expectedIds.AppendElement(ScrollableLayerGuid::NULL_SCROLL_ID); 266 for (int i = 0; i < 10; i++) { 267 ASSERT_EQ(expectedLayers[i], wrapper.GetLayer()); 268 ASSERT_EQ(expectedIds[i], wrapper.Metrics().GetScrollId()); 269 wrapper = wrapper.GetLastChild(); 270 } 271 ASSERT_FALSE(wrapper.IsValid()); 272 }