tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }