opacity_layer_unittests.cc 18.1 KB
Newer Older
1 2 3 4 5 6
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/flow/layers/opacity_layer.h"

7
#include "flutter/flow/layers/clip_rect_layer.h"
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
#include "flutter/flow/testing/layer_test.h"
#include "flutter/flow/testing/mock_layer.h"
#include "flutter/fml/macros.h"
#include "flutter/testing/mock_canvas.h"

namespace flutter {
namespace testing {

using OpacityLayerTest = LayerTest;

#ifndef NDEBUG
TEST_F(OpacityLayerTest, LeafLayer) {
  auto layer =
      std::make_shared<OpacityLayer>(SK_AlphaOPAQUE, SkPoint::Make(0.0f, 0.0f));

23 24 25
  EXPECT_DEATH_IF_SUPPORTED(
      layer->Preroll(preroll_context(), SkMatrix()),
      "\\!GetChildContainer\\(\\)->layers\\(\\)\\.empty\\(\\)");
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
}

TEST_F(OpacityLayerTest, PaintingEmptyLayerDies) {
  auto mock_layer = std::make_shared<MockLayer>(SkPath());
  auto layer =
      std::make_shared<OpacityLayer>(SK_AlphaOPAQUE, SkPoint::Make(0.0f, 0.0f));
  layer->Add(mock_layer);

  layer->Preroll(preroll_context(), SkMatrix());
  EXPECT_EQ(mock_layer->paint_bounds(), SkPath().getBounds());
  EXPECT_EQ(layer->paint_bounds(), mock_layer->paint_bounds());
  EXPECT_FALSE(mock_layer->needs_painting());
  EXPECT_FALSE(layer->needs_painting());

  EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
                            "needs_painting\\(\\)");
}

TEST_F(OpacityLayerTest, PaintBeforePreollDies) {
  SkPath child_path;
  child_path.addRect(5.0f, 6.0f, 20.5f, 21.5f);
  auto mock_layer = std::make_shared<MockLayer>(child_path);
  auto layer =
      std::make_shared<OpacityLayer>(SK_AlphaOPAQUE, SkPoint::Make(0.0f, 0.0f));
  layer->Add(mock_layer);

  EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
                            "needs_painting\\(\\)");
}
#endif

57 58
TEST_F(OpacityLayerTest, ChildIsCached) {
  const SkAlpha alpha_half = 255 / 2;
59 60
  auto initial_transform = SkMatrix::Translate(50.0, 25.5);
  auto other_transform = SkMatrix::Scale(1.0, 2.0);
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
  const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
  auto mock_layer = std::make_shared<MockLayer>(child_path);
  auto layer =
      std::make_shared<OpacityLayer>(alpha_half, SkPoint::Make(0.0f, 0.0f));
  layer->Add(mock_layer);

  SkMatrix cache_ctm = initial_transform;
  SkCanvas cache_canvas;
  cache_canvas.setMatrix(cache_ctm);
  SkCanvas other_canvas;
  other_canvas.setMatrix(other_transform);

  use_mock_raster_cache();

  EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
  EXPECT_FALSE(raster_cache()->Draw(mock_layer.get(), other_canvas));
  EXPECT_FALSE(raster_cache()->Draw(mock_layer.get(), cache_canvas));

  layer->Preroll(preroll_context(), initial_transform);

  EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)1);
  EXPECT_FALSE(raster_cache()->Draw(mock_layer.get(), other_canvas));
  EXPECT_TRUE(raster_cache()->Draw(mock_layer.get(), cache_canvas));
}

TEST_F(OpacityLayerTest, ChildrenNotCached) {
  const SkAlpha alpha_half = 255 / 2;
88 89
  auto initial_transform = SkMatrix::Translate(50.0, 25.5);
  auto other_transform = SkMatrix::Scale(1.0, 2.0);
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
  const SkPath child_path1 = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
  const SkPath child_path2 = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
  auto mock_layer1 = std::make_shared<MockLayer>(child_path1);
  auto mock_layer2 = std::make_shared<MockLayer>(child_path2);
  auto layer =
      std::make_shared<OpacityLayer>(alpha_half, SkPoint::Make(0.0f, 0.0f));
  layer->Add(mock_layer1);
  layer->Add(mock_layer2);

  SkMatrix cache_ctm = initial_transform;
  SkCanvas cache_canvas;
  cache_canvas.setMatrix(cache_ctm);
  SkCanvas other_canvas;
  other_canvas.setMatrix(other_transform);

  use_mock_raster_cache();

  EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
  EXPECT_FALSE(raster_cache()->Draw(mock_layer1.get(), other_canvas));
  EXPECT_FALSE(raster_cache()->Draw(mock_layer1.get(), cache_canvas));
  EXPECT_FALSE(raster_cache()->Draw(mock_layer2.get(), other_canvas));
  EXPECT_FALSE(raster_cache()->Draw(mock_layer2.get(), cache_canvas));

  layer->Preroll(preroll_context(), initial_transform);

  EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)1);
  EXPECT_FALSE(raster_cache()->Draw(mock_layer1.get(), other_canvas));
  EXPECT_FALSE(raster_cache()->Draw(mock_layer1.get(), cache_canvas));
  EXPECT_FALSE(raster_cache()->Draw(mock_layer2.get(), other_canvas));
  EXPECT_FALSE(raster_cache()->Draw(mock_layer2.get(), cache_canvas));
}

122 123 124
TEST_F(OpacityLayerTest, FullyOpaque) {
  const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
  const SkPoint layer_offset = SkPoint::Make(0.5f, 1.5f);
125
  const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 0.5f);
126
  const SkMatrix layer_transform =
127
      SkMatrix::Translate(layer_offset.fX, layer_offset.fY);
128 129 130 131
#ifndef SUPPORT_FRACTIONAL_TRANSLATION
  const SkMatrix integral_layer_transform = RasterCache::GetIntegralTransCTM(
      SkMatrix::Concat(initial_transform, layer_transform));
#endif
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
  const SkPaint child_paint = SkPaint(SkColors::kGreen);
  const SkRect expected_layer_bounds =
      layer_transform.mapRect(child_path.getBounds());
  auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
  auto layer = std::make_shared<OpacityLayer>(SK_AlphaOPAQUE, layer_offset);
  layer->Add(mock_layer);

  layer->Preroll(preroll_context(), initial_transform);
  EXPECT_EQ(mock_layer->paint_bounds(), child_path.getBounds());
  EXPECT_EQ(layer->paint_bounds(), expected_layer_bounds);
  EXPECT_TRUE(mock_layer->needs_painting());
  EXPECT_TRUE(layer->needs_painting());
  EXPECT_EQ(mock_layer->parent_matrix(),
            SkMatrix::Concat(initial_transform, layer_transform));
  EXPECT_EQ(mock_layer->parent_mutators(),
            std::vector({Mutator(layer_transform), Mutator(SK_AlphaOPAQUE)}));

  const SkPaint opacity_paint = SkPaint(SkColors::kBlack);  // A = 1.0f
  SkRect opacity_bounds;
  expected_layer_bounds.makeOffset(-layer_offset.fX, -layer_offset.fY)
      .roundOut(&opacity_bounds);
  auto expected_draw_calls = std::vector(
      {MockCanvas::DrawCall{0, MockCanvas::SaveData{1}},
       MockCanvas::DrawCall{1, MockCanvas::ConcatMatrixData{layer_transform}},
156 157 158 159
#ifndef SUPPORT_FRACTIONAL_TRANSLATION
       MockCanvas::DrawCall{
           1, MockCanvas::SetMatrixData{integral_layer_transform}},
#endif
160 161 162 163 164 165 166 167 168 169 170 171 172 173
       MockCanvas::DrawCall{
           1, MockCanvas::SaveLayerData{opacity_bounds, opacity_paint, nullptr,
                                        2}},
       MockCanvas::DrawCall{2,
                            MockCanvas::DrawPathData{child_path, child_paint}},
       MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}},
       MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}});
  layer->Paint(paint_context());
  EXPECT_EQ(mock_canvas().draw_calls(), expected_draw_calls);
}

TEST_F(OpacityLayerTest, FullyTransparent) {
  const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
  const SkPoint layer_offset = SkPoint::Make(0.5f, 1.5f);
174
  const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 0.5f);
175
  const SkMatrix layer_transform =
176
      SkMatrix::Translate(layer_offset.fX, layer_offset.fY);
177 178 179 180
#ifndef SUPPORT_FRACTIONAL_TRANSLATION
  const SkMatrix integral_layer_transform = RasterCache::GetIntegralTransCTM(
      SkMatrix::Concat(initial_transform, layer_transform));
#endif
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
  const SkPaint child_paint = SkPaint(SkColors::kGreen);
  const SkRect expected_layer_bounds =
      layer_transform.mapRect(child_path.getBounds());
  auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
  auto layer =
      std::make_shared<OpacityLayer>(SK_AlphaTRANSPARENT, layer_offset);
  layer->Add(mock_layer);

  layer->Preroll(preroll_context(), initial_transform);
  EXPECT_EQ(mock_layer->paint_bounds(), child_path.getBounds());
  EXPECT_EQ(layer->paint_bounds(), expected_layer_bounds);
  EXPECT_TRUE(mock_layer->needs_painting());
  EXPECT_TRUE(layer->needs_painting());
  EXPECT_EQ(mock_layer->parent_matrix(),
            SkMatrix::Concat(initial_transform, layer_transform));
  EXPECT_EQ(
      mock_layer->parent_mutators(),
      std::vector({Mutator(layer_transform), Mutator(SK_AlphaTRANSPARENT)}));

  auto expected_draw_calls = std::vector(
      {MockCanvas::DrawCall{0, MockCanvas::SaveData{1}},
       MockCanvas::DrawCall{1, MockCanvas::ConcatMatrixData{layer_transform}},
203 204 205 206
#ifndef SUPPORT_FRACTIONAL_TRANSLATION
       MockCanvas::DrawCall{
           1, MockCanvas::SetMatrixData{integral_layer_transform}},
#endif
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
       MockCanvas::DrawCall{1, MockCanvas::SaveData{2}},
       MockCanvas::DrawCall{
           2, MockCanvas::ClipRectData{kEmptyRect, SkClipOp::kIntersect,
                                       MockCanvas::kHard_ClipEdgeStyle}},
       MockCanvas::DrawCall{2,
                            MockCanvas::DrawPathData{child_path, child_paint}},
       MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}},
       MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}});
  layer->Paint(paint_context());
  EXPECT_EQ(mock_canvas().draw_calls(), expected_draw_calls);
}

TEST_F(OpacityLayerTest, HalfTransparent) {
  const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
  const SkPoint layer_offset = SkPoint::Make(0.5f, 1.5f);
222
  const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 0.5f);
223
  const SkMatrix layer_transform =
224
      SkMatrix::Translate(layer_offset.fX, layer_offset.fY);
225 226 227 228
#ifndef SUPPORT_FRACTIONAL_TRANSLATION
  const SkMatrix integral_layer_transform = RasterCache::GetIntegralTransCTM(
      SkMatrix::Concat(initial_transform, layer_transform));
#endif
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
  const SkPaint child_paint = SkPaint(SkColors::kGreen);
  const SkRect expected_layer_bounds =
      layer_transform.mapRect(child_path.getBounds());
  const SkAlpha alpha_half = 255 / 2;
  auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
  auto layer = std::make_shared<OpacityLayer>(alpha_half, layer_offset);
  layer->Add(mock_layer);

  layer->Preroll(preroll_context(), initial_transform);
  EXPECT_EQ(mock_layer->paint_bounds(), child_path.getBounds());
  EXPECT_EQ(layer->paint_bounds(), expected_layer_bounds);
  EXPECT_TRUE(mock_layer->needs_painting());
  EXPECT_TRUE(layer->needs_painting());
  EXPECT_EQ(mock_layer->parent_matrix(),
            SkMatrix::Concat(initial_transform, layer_transform));
  EXPECT_EQ(mock_layer->parent_mutators(),
            std::vector({Mutator(layer_transform), Mutator(alpha_half)}));

  const SkPaint opacity_paint =
      SkPaint(SkColor4f::FromColor(SkColorSetA(SK_ColorBLACK, alpha_half)));
  SkRect opacity_bounds;
  expected_layer_bounds.makeOffset(-layer_offset.fX, -layer_offset.fY)
      .roundOut(&opacity_bounds);
  auto expected_draw_calls = std::vector(
      {MockCanvas::DrawCall{0, MockCanvas::SaveData{1}},
       MockCanvas::DrawCall{1, MockCanvas::ConcatMatrixData{layer_transform}},
255 256 257 258
#ifndef SUPPORT_FRACTIONAL_TRANSLATION
       MockCanvas::DrawCall{
           1, MockCanvas::SetMatrixData{integral_layer_transform}},
#endif
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
       MockCanvas::DrawCall{
           1, MockCanvas::SaveLayerData{opacity_bounds, opacity_paint, nullptr,
                                        2}},
       MockCanvas::DrawCall{2,
                            MockCanvas::DrawPathData{child_path, child_paint}},
       MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}},
       MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}});
  layer->Paint(paint_context());
  EXPECT_EQ(mock_canvas().draw_calls(), expected_draw_calls);
}

TEST_F(OpacityLayerTest, Nested) {
  const SkPath child1_path = SkPath().addRect(SkRect::MakeWH(5.0f, 6.0f));
  const SkPath child2_path = SkPath().addRect(SkRect::MakeWH(2.0f, 7.0f));
  const SkPath child3_path = SkPath().addRect(SkRect::MakeWH(6.0f, 6.0f));
  const SkPoint layer1_offset = SkPoint::Make(0.5f, 1.5f);
  const SkPoint layer2_offset = SkPoint::Make(2.5f, 0.5f);
276
  const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 0.5f);
277
  const SkMatrix layer1_transform =
278
      SkMatrix::Translate(layer1_offset.fX, layer1_offset.fY);
279
  const SkMatrix layer2_transform =
280
      SkMatrix::Translate(layer2_offset.fX, layer2_offset.fY);
281 282 283 284 285 286 287
#ifndef SUPPORT_FRACTIONAL_TRANSLATION
  const SkMatrix integral_layer1_transform = RasterCache::GetIntegralTransCTM(
      SkMatrix::Concat(initial_transform, layer1_transform));
  const SkMatrix integral_layer2_transform = RasterCache::GetIntegralTransCTM(
      SkMatrix::Concat(SkMatrix::Concat(initial_transform, layer1_transform),
                       layer2_transform));
#endif
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
  const SkPaint child1_paint = SkPaint(SkColors::kRed);
  const SkPaint child2_paint = SkPaint(SkColors::kBlue);
  const SkPaint child3_paint = SkPaint(SkColors::kGreen);
  const SkAlpha alpha1 = 155;
  const SkAlpha alpha2 = 224;
  auto mock_layer1 = std::make_shared<MockLayer>(child1_path, child1_paint);
  auto mock_layer2 = std::make_shared<MockLayer>(child2_path, child2_paint);
  auto mock_layer3 = std::make_shared<MockLayer>(child3_path, child3_paint);
  auto layer1 = std::make_shared<OpacityLayer>(alpha1, layer1_offset);
  auto layer2 = std::make_shared<OpacityLayer>(alpha2, layer2_offset);
  layer2->Add(mock_layer2);
  layer1->Add(mock_layer1);
  layer1->Add(layer2);
  layer1->Add(mock_layer3);  // Ensure something is processed after recursion

  const SkRect expected_layer2_bounds =
      layer2_transform.mapRect(child2_path.getBounds());
  SkRect expected_layer1_bounds = expected_layer2_bounds;
  expected_layer1_bounds.join(child1_path.getBounds());
  expected_layer1_bounds.join(child3_path.getBounds());
  expected_layer1_bounds = layer1_transform.mapRect(expected_layer1_bounds);
  layer1->Preroll(preroll_context(), initial_transform);
  EXPECT_EQ(mock_layer1->paint_bounds(), child1_path.getBounds());
  EXPECT_EQ(mock_layer2->paint_bounds(), child2_path.getBounds());
  EXPECT_EQ(mock_layer3->paint_bounds(), child3_path.getBounds());
  EXPECT_EQ(layer1->paint_bounds(), expected_layer1_bounds);
  EXPECT_EQ(layer2->paint_bounds(), expected_layer2_bounds);
  EXPECT_TRUE(mock_layer1->needs_painting());
  EXPECT_TRUE(mock_layer2->needs_painting());
  EXPECT_TRUE(mock_layer3->needs_painting());
  EXPECT_TRUE(layer1->needs_painting());
  EXPECT_TRUE(layer2->needs_painting());
  EXPECT_EQ(mock_layer1->parent_matrix(),
            SkMatrix::Concat(initial_transform, layer1_transform));
  //   EXPECT_EQ(mock_layer1->parent_mutators(),
  //             std::vector({Mutator(layer1_transform), Mutator(alpha1)}));
  EXPECT_EQ(
      mock_layer2->parent_matrix(),
      SkMatrix::Concat(SkMatrix::Concat(initial_transform, layer1_transform),
                       layer2_transform));
  //   EXPECT_EQ(mock_layer2->parent_mutators(),
  //             std::vector({Mutator(layer1_transform), Mutator(alpha1),
  //                          Mutator(layer2_transform), Mutator(alpha2)}));
  EXPECT_EQ(mock_layer3->parent_matrix(),
            SkMatrix::Concat(initial_transform, layer1_transform));
  //   EXPECT_EQ(mock_layer3->parent_mutators(),
  //             std::vector({Mutator(layer1_transform), Mutator(alpha1)}));

  const SkPaint opacity1_paint =
      SkPaint(SkColor4f::FromColor(SkColorSetA(SK_ColorBLACK, alpha1)));
  const SkPaint opacity2_paint =
      SkPaint(SkColor4f::FromColor(SkColorSetA(SK_ColorBLACK, alpha2)));
  SkRect opacity1_bounds, opacity2_bounds;
  expected_layer1_bounds.makeOffset(-layer1_offset.fX, -layer1_offset.fY)
      .roundOut(&opacity1_bounds);
  expected_layer2_bounds.makeOffset(-layer2_offset.fX, -layer2_offset.fY)
      .roundOut(&opacity2_bounds);
  auto expected_draw_calls = std::vector(
      {MockCanvas::DrawCall{0, MockCanvas::SaveData{1}},
       MockCanvas::DrawCall{1, MockCanvas::ConcatMatrixData{layer1_transform}},
348 349 350 351
#ifndef SUPPORT_FRACTIONAL_TRANSLATION
       MockCanvas::DrawCall{
           1, MockCanvas::SetMatrixData{integral_layer1_transform}},
#endif
352 353 354 355 356 357 358
       MockCanvas::DrawCall{
           1, MockCanvas::SaveLayerData{opacity1_bounds, opacity1_paint,
                                        nullptr, 2}},
       MockCanvas::DrawCall{
           2, MockCanvas::DrawPathData{child1_path, child1_paint}},
       MockCanvas::DrawCall{2, MockCanvas::SaveData{3}},
       MockCanvas::DrawCall{3, MockCanvas::ConcatMatrixData{layer2_transform}},
359 360 361 362
#ifndef SUPPORT_FRACTIONAL_TRANSLATION
       MockCanvas::DrawCall{
           3, MockCanvas::SetMatrixData{integral_layer2_transform}},
#endif
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
       MockCanvas::DrawCall{
           3, MockCanvas::SaveLayerData{opacity2_bounds, opacity2_paint,
                                        nullptr, 4}},
       MockCanvas::DrawCall{
           4, MockCanvas::DrawPathData{child2_path, child2_paint}},
       MockCanvas::DrawCall{4, MockCanvas::RestoreData{3}},
       MockCanvas::DrawCall{3, MockCanvas::RestoreData{2}},
       MockCanvas::DrawCall{
           2, MockCanvas::DrawPathData{child3_path, child3_paint}},
       MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}},
       MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}});
  layer1->Paint(paint_context());
  EXPECT_EQ(mock_canvas().draw_calls(), expected_draw_calls);
}

378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396
TEST_F(OpacityLayerTest, Readback) {
  auto initial_transform = SkMatrix();
  auto layer = std::make_shared<OpacityLayer>(kOpaque_SkAlphaType, SkPoint());
  layer->Add(std::make_shared<MockLayer>(SkPath()));

  // OpacityLayer does not read from surface
  preroll_context()->surface_needs_readback = false;
  layer->Preroll(preroll_context(), initial_transform);
  EXPECT_FALSE(preroll_context()->surface_needs_readback);

  // OpacityLayer blocks child with readback
  auto mock_layer =
      std::make_shared<MockLayer>(SkPath(), SkPaint(), false, false, true);
  layer->Add(mock_layer);
  preroll_context()->surface_needs_readback = false;
  layer->Preroll(preroll_context(), initial_transform);
  EXPECT_FALSE(preroll_context()->surface_needs_readback);
}

397 398 399 400 401 402 403 404 405 406 407 408 409
TEST_F(OpacityLayerTest, CullRectIsTransformed) {
  auto clipRectLayer = std::make_shared<ClipRectLayer>(
      SkRect::MakeLTRB(0, 0, 10, 10), flutter::hardEdge);
  auto opacityLayer =
      std::make_shared<OpacityLayer>(128, SkPoint::Make(20, 20));
  auto mockLayer = std::make_shared<MockLayer>(SkPath());
  clipRectLayer->Add(opacityLayer);
  opacityLayer->Add(mockLayer);
  clipRectLayer->Preroll(preroll_context(), SkMatrix::I());
  EXPECT_EQ(mockLayer->parent_cull_rect().fLeft, -20);
  EXPECT_EQ(mockLayer->parent_cull_rect().fTop, -20);
}

410 411
}  // namespace testing
}  // namespace flutter