Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/tests/gtest/TestLayers.cpp
Line
Count
Source (jump to first uncovered line)
1
/* vim:set ts=2 sw=2 sts=2 et: */
2
/* Any copyright is dedicated to the Public Domain.
3
 * http://creativecommons.org/publicdomain/zero/1.0/
4
 */
5
6
#include "TestLayers.h"
7
#include "gtest/gtest.h"
8
#include "gmock/gmock.h"
9
#include "LayerUserData.h"
10
#include "mozilla/layers/LayerMetricsWrapper.h"
11
#include "mozilla/layers/CompositorBridgeParent.h"
12
13
using namespace mozilla;
14
using namespace mozilla::gfx;
15
using namespace mozilla::layers;
16
17
class TestContainerLayer: public ContainerLayer {
18
public:
19
  explicit TestContainerLayer(LayerManager* aManager)
20
    : ContainerLayer(aManager, nullptr)
21
0
  {}
22
23
0
  virtual const char* Name() const {
24
0
    return "TestContainerLayer";
25
0
  }
26
27
0
  virtual LayerType GetType() const {
28
0
    return TYPE_CONTAINER;
29
0
  }
30
31
0
  virtual void ComputeEffectiveTransforms(const Matrix4x4& aTransformToSurface) {
32
0
    DefaultComputeEffectiveTransforms(aTransformToSurface);
33
0
  }
34
};
35
36
class TestPaintedLayer: public PaintedLayer {
37
public:
38
  explicit TestPaintedLayer(LayerManager* aManager)
39
    : PaintedLayer(aManager, nullptr)
40
0
  {}
41
42
0
  virtual const char* Name() const {
43
0
    return "TestPaintedLayer";
44
0
  }
45
46
0
  virtual LayerType GetType() const {
47
0
    return TYPE_PAINTED;
48
0
  }
49
50
0
  virtual void InvalidateRegion(const nsIntRegion& aRegion) {
51
0
    MOZ_CRASH();
52
0
  }
53
};
54
55
class TestLayerManager: public LayerManager {
56
public:
57
  TestLayerManager()
58
    : LayerManager()
59
0
  {}
60
61
0
  virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT) { return false; }
62
0
  virtual already_AddRefed<ContainerLayer> CreateContainerLayer() {
63
0
    RefPtr<ContainerLayer> layer = new TestContainerLayer(this);
64
0
    return layer.forget();
65
0
  }
66
0
  virtual void GetBackendName(nsAString& aName) {}
67
0
  virtual LayersBackend GetBackendType() { return LayersBackend::LAYERS_BASIC; }
68
0
  virtual bool BeginTransaction() { return true; }
69
0
  virtual already_AddRefed<ImageLayer> CreateImageLayer() {
70
0
    MOZ_CRASH("Not implemented.");
71
0
  }
72
0
  virtual already_AddRefed<PaintedLayer> CreatePaintedLayer() {
73
0
    RefPtr<PaintedLayer> layer = new TestPaintedLayer(this);
74
0
    return layer.forget();
75
0
  }
76
0
  virtual already_AddRefed<ColorLayer> CreateColorLayer() {
77
0
    MOZ_CRASH("Not implemented.");
78
0
  }
79
0
  virtual void SetRoot(Layer* aLayer) {}
80
0
  virtual bool BeginTransactionWithTarget(gfxContext* aTarget) { return true; }
81
0
  virtual already_AddRefed<CanvasLayer> CreateCanvasLayer() {
82
0
    MOZ_CRASH("Not implemented.");
83
0
  }
84
  virtual void EndTransaction(DrawPaintedLayerCallback aCallback,
85
                              void* aCallbackData,
86
0
                              EndTransactionFlags aFlags = END_DEFAULT) {}
87
0
  virtual int32_t GetMaxTextureSize() const { return 0; }
88
};
89
90
class TestUserData: public LayerUserData {
91
public:
92
  MOCK_METHOD0(Die, void());
93
0
  virtual ~TestUserData() { Die(); }
94
};
95
96
97
0
TEST(Layers, LayerConstructor) {
98
0
  TestContainerLayer layer(nullptr);
99
0
}
100
101
0
TEST(Layers, Defaults) {
102
0
  TestContainerLayer layer(nullptr);
103
0
  ASSERT_EQ(1.0, layer.GetOpacity());
104
0
  ASSERT_EQ(1.0f, layer.GetPostXScale());
105
0
  ASSERT_EQ(1.0f, layer.GetPostYScale());
106
0
107
0
  ASSERT_EQ(nullptr, layer.GetNextSibling());
108
0
  ASSERT_EQ(nullptr, layer.GetPrevSibling());
109
0
  ASSERT_EQ(nullptr, layer.GetFirstChild());
110
0
  ASSERT_EQ(nullptr, layer.GetLastChild());
111
0
}
112
113
0
TEST(Layers, Transform) {
114
0
  TestContainerLayer layer(nullptr);
115
0
116
0
  Matrix4x4 identity;
117
0
  ASSERT_EQ(true, identity.IsIdentity());
118
0
119
0
  ASSERT_EQ(identity, layer.GetTransform());
120
0
}
121
122
0
TEST(Layers, Type) {
123
0
  TestContainerLayer layer(nullptr);
124
0
  ASSERT_EQ(nullptr, layer.AsPaintedLayer());
125
0
  ASSERT_EQ(nullptr, layer.AsRefLayer());
126
0
  ASSERT_EQ(nullptr, layer.AsColorLayer());
127
0
}
128
129
0
TEST(Layers, UserData) {
130
0
  UniquePtr<TestContainerLayer> layerPtr(new TestContainerLayer(nullptr));
131
0
  TestContainerLayer& layer = *layerPtr;
132
0
133
0
  void* key1 = (void*)1;
134
0
  void* key2 = (void*)2;
135
0
  void* key3 = (void*)3;
136
0
137
0
  ASSERT_EQ(nullptr, layer.GetUserData(key1));
138
0
  ASSERT_EQ(nullptr, layer.GetUserData(key2));
139
0
  ASSERT_EQ(nullptr, layer.GetUserData(key3));
140
0
141
0
  TestUserData* data1 = new TestUserData;
142
0
  TestUserData* data2 = new TestUserData;
143
0
  TestUserData* data3 = new TestUserData;
144
0
145
0
  layer.SetUserData(key1, data1);
146
0
  layer.SetUserData(key2, data2);
147
0
  layer.SetUserData(key3, data3);
148
0
149
0
  // Also checking that the user data is returned but not free'd
150
0
  UniquePtr<LayerUserData> d1(layer.RemoveUserData(key1));
151
0
  UniquePtr<LayerUserData> d2(layer.RemoveUserData(key2));
152
0
  UniquePtr<LayerUserData> d3(layer.RemoveUserData(key3));
153
0
  ASSERT_EQ(data1, d1.get());
154
0
  ASSERT_EQ(data2, d2.get());
155
0
  ASSERT_EQ(data3, d3.get());
156
0
157
0
  layer.SetUserData(key1, d1.release());
158
0
  layer.SetUserData(key2, d2.release());
159
0
  layer.SetUserData(key3, d3.release());
160
0
161
0
  // Layer has ownership of data1-3, check that they are destroyed
162
0
  EXPECT_CALL(*data1, Die());
163
0
  EXPECT_CALL(*data2, Die());
164
0
  EXPECT_CALL(*data3, Die());
165
0
}
166
167
static
168
0
already_AddRefed<Layer> CreateLayer(char aLayerType, LayerManager* aManager) {
169
0
  RefPtr<Layer> layer = nullptr;
170
0
  if (aLayerType == 'c') {
171
0
    layer = aManager->CreateContainerLayer();
172
0
  } else if (aLayerType == 't') {
173
0
    layer = aManager->CreatePaintedLayer();
174
0
  } else if (aLayerType == 'o') {
175
0
    layer = aManager->CreateColorLayer();
176
0
  }
177
0
  return layer.forget();
178
0
}
179
180
already_AddRefed<Layer> CreateLayerTree(
181
    const char* aLayerTreeDescription,
182
    nsIntRegion* aVisibleRegions,
183
    const Matrix4x4* aTransforms,
184
    RefPtr<LayerManager>& manager,
185
0
    nsTArray<RefPtr<Layer> >& aLayersOut) {
186
0
187
0
  aLayersOut.Clear();
188
0
189
0
  if (!manager) {
190
0
    manager = new TestLayerManager();
191
0
  }
192
0
193
0
  RefPtr<Layer> rootLayer = nullptr;
194
0
  RefPtr<ContainerLayer> parentContainerLayer = nullptr;
195
0
  RefPtr<Layer> lastLayer = nullptr;
196
0
  int layerNumber = 0;
197
0
  for (size_t i = 0; i < strlen(aLayerTreeDescription); i++) {
198
0
    if (aLayerTreeDescription[i] == '(') {
199
0
      if (!lastLayer) {
200
0
        printf("Syntax error, likely '(' character isn't preceded by a container.\n");
201
0
        MOZ_CRASH();
202
0
      }
203
0
      parentContainerLayer = lastLayer->AsContainerLayer();
204
0
      if (!parentContainerLayer) {
205
0
        printf("Layer before '(' must be a container.\n");
206
0
        MOZ_CRASH();
207
0
      }
208
0
    } else if (aLayerTreeDescription[i] == ')') {
209
0
      parentContainerLayer = parentContainerLayer->GetParent();
210
0
      lastLayer = nullptr;
211
0
    } else {
212
0
      RefPtr<Layer> layer = CreateLayer(aLayerTreeDescription[i], manager.get());
213
0
      if (aVisibleRegions) {
214
0
        layer->SetVisibleRegion(LayerIntRegion::FromUnknownRegion(aVisibleRegions[layerNumber]));
215
0
        layer->SetEventRegions(EventRegions(aVisibleRegions[layerNumber]));
216
0
      }
217
0
      if (aTransforms) {
218
0
        layer->SetBaseTransform(aTransforms[layerNumber]);
219
0
      }
220
0
      aLayersOut.AppendElement(layer);
221
0
      layerNumber++;
222
0
      if (rootLayer && !parentContainerLayer) {
223
0
        MOZ_CRASH();
224
0
      }
225
0
      if (!rootLayer) {
226
0
        rootLayer = layer;
227
0
      }
228
0
      if (parentContainerLayer) {
229
0
        parentContainerLayer->InsertAfter(layer, parentContainerLayer->GetLastChild());
230
0
        layer->SetParent(parentContainerLayer);
231
0
      }
232
0
      lastLayer = layer;
233
0
    }
234
0
  }
235
0
  if (rootLayer) {
236
0
    rootLayer->ComputeEffectiveTransforms(Matrix4x4());
237
0
    manager->SetRoot(rootLayer);
238
0
    if (rootLayer->AsHostLayer()) {
239
0
      // Only perform this for LayerManagerComposite
240
0
      CompositorBridgeParent::SetShadowProperties(rootLayer);
241
0
    }
242
0
  }
243
0
  return rootLayer.forget();
244
0
}
245
246
0
TEST(Layers, LayerTree) {
247
0
  const char* layerTreeSyntax = "c(c(tt))";
248
0
  nsIntRegion layerVisibleRegion[] = {
249
0
    nsIntRegion(IntRect(0,0,100,100)),
250
0
    nsIntRegion(IntRect(0,0,100,100)),
251
0
    nsIntRegion(IntRect(0,0,100,100)),
252
0
    nsIntRegion(IntRect(10,10,20,20)),
253
0
  };
254
0
  Matrix4x4 transforms[] = {
255
0
    Matrix4x4(),
256
0
    Matrix4x4(),
257
0
    Matrix4x4(),
258
0
    Matrix4x4(),
259
0
  };
260
0
  nsTArray<RefPtr<Layer> > layers;
261
0
262
0
  RefPtr<LayerManager> lm;
263
0
  RefPtr<Layer> root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, transforms, lm, layers);
264
0
265
0
  // B2G g++ doesn't like ASSERT_NE with nullptr directly. It thinks it's
266
0
  // an int.
267
0
  Layer* nullLayer = nullptr;
268
0
  ASSERT_NE(nullLayer, layers[0]->AsContainerLayer());
269
0
  ASSERT_NE(nullLayer, layers[1]->AsContainerLayer());
270
0
  ASSERT_NE(nullLayer, layers[2]->AsPaintedLayer());
271
0
  ASSERT_NE(nullLayer, layers[3]->AsPaintedLayer());
272
0
}
273
274
0
static void ValidateTreePointers(Layer* aLayer) {
275
0
  if (aLayer->GetNextSibling()) {
276
0
    ASSERT_EQ(aLayer, aLayer->GetNextSibling()->GetPrevSibling());
277
0
  } else if (aLayer->GetParent()) {
278
0
    ASSERT_EQ(aLayer, aLayer->GetParent()->GetLastChild());
279
0
  }
280
0
  if (aLayer->GetPrevSibling()) {
281
0
    ASSERT_EQ(aLayer, aLayer->GetPrevSibling()->GetNextSibling());
282
0
  } else if (aLayer->GetParent()) {
283
0
    ASSERT_EQ(aLayer, aLayer->GetParent()->GetFirstChild());
284
0
  }
285
0
  if (aLayer->GetFirstChild()) {
286
0
    ASSERT_EQ(aLayer, aLayer->GetFirstChild()->GetParent());
287
0
  }
288
0
  if (aLayer->GetLastChild()) {
289
0
    ASSERT_EQ(aLayer, aLayer->GetLastChild()->GetParent());
290
0
  }
291
0
}
292
293
0
static void ValidateTreePointers(nsTArray<RefPtr<Layer> >& aLayers) {
294
0
  for (uint32_t i = 0; i < aLayers.Length(); i++) {
295
0
    ValidateTreePointers(aLayers[i]);
296
0
  }
297
0
}
298
299
0
TEST(Layers, RepositionChild) {
300
0
  const char* layerTreeSyntax = "c(ttt)";
301
0
302
0
  nsTArray<RefPtr<Layer> > layers;
303
0
  RefPtr<LayerManager> lm;
304
0
  RefPtr<Layer> root = CreateLayerTree(layerTreeSyntax, nullptr, nullptr, lm, layers);
305
0
  ContainerLayer* parent = root->AsContainerLayer();
306
0
  ValidateTreePointers(layers);
307
0
308
0
  // tree is currently like this (using indexes into layers):
309
0
  //   0
310
0
  // 1 2 3
311
0
  ASSERT_EQ(layers[2], layers[1]->GetNextSibling());
312
0
  ASSERT_EQ(layers[3], layers[2]->GetNextSibling());
313
0
  ASSERT_EQ(nullptr, layers[3]->GetNextSibling());
314
0
315
0
  parent->RepositionChild(layers[1], layers[3]);
316
0
  ValidateTreePointers(layers);
317
0
318
0
  // now the tree is like this:
319
0
  //   0
320
0
  // 2 3 1
321
0
  ASSERT_EQ(layers[3], layers[2]->GetNextSibling());
322
0
  ASSERT_EQ(layers[1], layers[3]->GetNextSibling());
323
0
  ASSERT_EQ(nullptr, layers[1]->GetNextSibling());
324
0
325
0
  parent->RepositionChild(layers[3], layers[2]);
326
0
  ValidateTreePointers(layers);
327
0
328
0
  // no change
329
0
  ASSERT_EQ(layers[3], layers[2]->GetNextSibling());
330
0
  ASSERT_EQ(layers[1], layers[3]->GetNextSibling());
331
0
  ASSERT_EQ(nullptr, layers[1]->GetNextSibling());
332
0
333
0
  parent->RepositionChild(layers[3], layers[1]);
334
0
  ValidateTreePointers(layers);
335
0
336
0
  //   0
337
0
  // 2 1 3
338
0
  ASSERT_EQ(layers[1], layers[2]->GetNextSibling());
339
0
  ASSERT_EQ(layers[3], layers[1]->GetNextSibling());
340
0
  ASSERT_EQ(nullptr, layers[3]->GetNextSibling());
341
0
342
0
  parent->RepositionChild(layers[3], nullptr);
343
0
  ValidateTreePointers(layers);
344
0
345
0
  //   0
346
0
  // 3 2 1
347
0
  ASSERT_EQ(layers[2], layers[3]->GetNextSibling());
348
0
  ASSERT_EQ(layers[1], layers[2]->GetNextSibling());
349
0
  ASSERT_EQ(nullptr, layers[1]->GetNextSibling());
350
0
}
351
352
class LayerMetricsWrapperTester : public ::testing::Test {
353
protected:
354
0
  virtual void SetUp() {
355
0
    // This ensures ScrollMetadata::sNullMetadata is initialized.
356
0
    gfxPlatform::GetPlatform();
357
0
  }
358
};
359
360
0
TEST_F(LayerMetricsWrapperTester, SimpleTree) {
361
0
  nsTArray<RefPtr<Layer> > layers;
362
0
  RefPtr<LayerManager> lm;
363
0
  RefPtr<Layer> root = CreateLayerTree("c(c(c(tt)c(t)))", nullptr, nullptr, lm, layers);
364
0
  LayerMetricsWrapper wrapper(root);
365
0
366
0
  ASSERT_EQ(root.get(), wrapper.GetLayer());
367
0
  wrapper = wrapper.GetFirstChild();
368
0
  ASSERT_EQ(layers[1].get(), wrapper.GetLayer());
369
0
  ASSERT_FALSE(wrapper.GetNextSibling().IsValid());
370
0
  wrapper = wrapper.GetFirstChild();
371
0
  ASSERT_EQ(layers[2].get(), wrapper.GetLayer());
372
0
  wrapper = wrapper.GetFirstChild();
373
0
  ASSERT_EQ(layers[3].get(), wrapper.GetLayer());
374
0
  ASSERT_FALSE(wrapper.GetFirstChild().IsValid());
375
0
  wrapper = wrapper.GetNextSibling();
376
0
  ASSERT_EQ(layers[4].get(), wrapper.GetLayer());
377
0
  ASSERT_FALSE(wrapper.GetNextSibling().IsValid());
378
0
  wrapper = wrapper.GetParent();
379
0
  ASSERT_EQ(layers[2].get(), wrapper.GetLayer());
380
0
  wrapper = wrapper.GetNextSibling();
381
0
  ASSERT_EQ(layers[5].get(), wrapper.GetLayer());
382
0
  ASSERT_FALSE(wrapper.GetNextSibling().IsValid());
383
0
  wrapper = wrapper.GetLastChild();
384
0
  ASSERT_EQ(layers[6].get(), wrapper.GetLayer());
385
0
  wrapper = wrapper.GetParent();
386
0
  ASSERT_EQ(layers[5].get(), wrapper.GetLayer());
387
0
  LayerMetricsWrapper layer5 = wrapper;
388
0
  wrapper = wrapper.GetPrevSibling();
389
0
  ASSERT_EQ(layers[2].get(), wrapper.GetLayer());
390
0
  wrapper = wrapper.GetParent();
391
0
  ASSERT_EQ(layers[1].get(), wrapper.GetLayer());
392
0
  ASSERT_TRUE(layer5 == wrapper.GetLastChild());
393
0
  LayerMetricsWrapper rootWrapper(root);
394
0
  ASSERT_TRUE(rootWrapper == wrapper.GetParent());
395
0
}
396
397
static ScrollMetadata
398
0
MakeMetadata(FrameMetrics::ViewID aId) {
399
0
  ScrollMetadata metadata;
400
0
  metadata.GetMetrics().SetScrollId(aId);
401
0
  return metadata;
402
0
}
403
404
0
TEST_F(LayerMetricsWrapperTester, MultiFramemetricsTree) {
405
0
  nsTArray<RefPtr<Layer> > layers;
406
0
  RefPtr<LayerManager> lm;
407
0
  RefPtr<Layer> root = CreateLayerTree("c(c(c(tt)c(t)))", nullptr, nullptr, lm, layers);
408
0
409
0
  nsTArray<ScrollMetadata> metadata;
410
0
  metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::START_SCROLL_ID + 0)); // topmost of root layer
411
0
  metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::NULL_SCROLL_ID));
412
0
  metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::START_SCROLL_ID + 1));
413
0
  metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::START_SCROLL_ID + 2));
414
0
  metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::NULL_SCROLL_ID));
415
0
  metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::NULL_SCROLL_ID));      // bottom of root layer
416
0
  root->SetScrollMetadata(metadata);
417
0
418
0
  metadata.Clear();
419
0
  metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::START_SCROLL_ID + 3));
420
0
  layers[1]->SetScrollMetadata(metadata);
421
0
422
0
  metadata.Clear();
423
0
  metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::NULL_SCROLL_ID));
424
0
  metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::START_SCROLL_ID + 4));
425
0
  layers[2]->SetScrollMetadata(metadata);
426
0
427
0
  metadata.Clear();
428
0
  metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::START_SCROLL_ID + 5));
429
0
  layers[4]->SetScrollMetadata(metadata);
430
0
431
0
  metadata.Clear();
432
0
  metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::START_SCROLL_ID + 6));
433
0
  layers[5]->SetScrollMetadata(metadata);
434
0
435
0
  LayerMetricsWrapper wrapper(root, LayerMetricsWrapper::StartAt::TOP);
436
0
  nsTArray<Layer*> expectedLayers;
437
0
  expectedLayers.AppendElement(layers[0].get());
438
0
  expectedLayers.AppendElement(layers[0].get());
439
0
  expectedLayers.AppendElement(layers[0].get());
440
0
  expectedLayers.AppendElement(layers[0].get());
441
0
  expectedLayers.AppendElement(layers[0].get());
442
0
  expectedLayers.AppendElement(layers[0].get());
443
0
  expectedLayers.AppendElement(layers[1].get());
444
0
  expectedLayers.AppendElement(layers[2].get());
445
0
  expectedLayers.AppendElement(layers[2].get());
446
0
  expectedLayers.AppendElement(layers[3].get());
447
0
  nsTArray<FrameMetrics::ViewID> expectedIds;
448
0
  expectedIds.AppendElement(FrameMetrics::START_SCROLL_ID + 0);
449
0
  expectedIds.AppendElement(FrameMetrics::NULL_SCROLL_ID);
450
0
  expectedIds.AppendElement(FrameMetrics::START_SCROLL_ID + 1);
451
0
  expectedIds.AppendElement(FrameMetrics::START_SCROLL_ID + 2);
452
0
  expectedIds.AppendElement(FrameMetrics::NULL_SCROLL_ID);
453
0
  expectedIds.AppendElement(FrameMetrics::NULL_SCROLL_ID);
454
0
  expectedIds.AppendElement(FrameMetrics::START_SCROLL_ID + 3);
455
0
  expectedIds.AppendElement(FrameMetrics::NULL_SCROLL_ID);
456
0
  expectedIds.AppendElement(FrameMetrics::START_SCROLL_ID + 4);
457
0
  expectedIds.AppendElement(FrameMetrics::NULL_SCROLL_ID);
458
0
  for (int i = 0; i < 10; i++) {
459
0
    ASSERT_EQ(expectedLayers[i], wrapper.GetLayer());
460
0
    ASSERT_EQ(expectedIds[i], wrapper.Metrics().GetScrollId());
461
0
    wrapper = wrapper.GetFirstChild();
462
0
  }
463
0
  ASSERT_FALSE(wrapper.IsValid());
464
0
465
0
  wrapper = LayerMetricsWrapper(root, LayerMetricsWrapper::StartAt::BOTTOM);
466
0
  for (int i = 5; i < 10; i++) {
467
0
    ASSERT_EQ(expectedLayers[i], wrapper.GetLayer());
468
0
    ASSERT_EQ(expectedIds[i], wrapper.Metrics().GetScrollId());
469
0
    wrapper = wrapper.GetFirstChild();
470
0
  }
471
0
  ASSERT_FALSE(wrapper.IsValid());
472
0
473
0
  wrapper = LayerMetricsWrapper(layers[4], LayerMetricsWrapper::StartAt::BOTTOM);
474
0
  ASSERT_EQ(FrameMetrics::START_SCROLL_ID + 5, wrapper.Metrics().GetScrollId());
475
0
  wrapper = wrapper.GetParent();
476
0
  ASSERT_EQ(FrameMetrics::START_SCROLL_ID + 4, wrapper.Metrics().GetScrollId());
477
0
  ASSERT_EQ(layers[2].get(), wrapper.GetLayer());
478
0
  ASSERT_FALSE(wrapper.GetNextSibling().IsValid());
479
0
  wrapper = wrapper.GetParent();
480
0
  ASSERT_EQ(FrameMetrics::NULL_SCROLL_ID, wrapper.Metrics().GetScrollId());
481
0
  ASSERT_EQ(layers[2].get(), wrapper.GetLayer());
482
0
  wrapper = wrapper.GetNextSibling();
483
0
  ASSERT_EQ(FrameMetrics::START_SCROLL_ID + 6, wrapper.Metrics().GetScrollId());
484
0
  ASSERT_EQ(layers[5].get(), wrapper.GetLayer());
485
0
}