blob: 24b7db407b98b664c03744c275ad0e333eb05e85 [file] [log] [blame]
// 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/clip_path_layer.h"
#include "flutter/flow/layers/clip_rect_layer.h"
#include "flutter/flow/layers/clip_rrect_layer.h"
#include "flutter/flow/layers/physical_shape_layer.h"
#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 CheckerBoardLayerTest = LayerTest;
#ifndef NDEBUG
TEST_F(CheckerBoardLayerTest, ClipRectSaveLayerNotCheckBoard) {
const SkMatrix initial_matrix = SkMatrix::Translate(0.5f, 1.0f);
const SkRect cull_bounds = SkRect::MakeXYWH(0.0, 0.0, 2.0, 4.0);
const SkRect child_bounds = SkRect::MakeXYWH(2.5, 5.0, 4.5, 4.0);
const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
const SkPath child_path = SkPath().addRect(child_bounds);
const SkPaint child_paint = SkPaint(SkColors::kYellow);
const SkPaint clip_paint;
auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
auto layer = std::make_shared<ClipRectLayer>(layer_bounds,
Clip::antiAliasWithSaveLayer);
layer->Add(mock_layer);
SkRect intersect_bounds = layer_bounds;
SkRect child_intersect_bounds = layer_bounds;
intersect_bounds.intersect(cull_bounds);
child_intersect_bounds.intersect(child_bounds);
preroll_context()->cull_rect = cull_bounds; // Cull child
layer->Preroll(preroll_context(), initial_matrix);
EXPECT_EQ(preroll_context()->cull_rect, cull_bounds); // Untouched
EXPECT_TRUE(preroll_context()->mutators_stack.is_empty()); // Untouched
EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
EXPECT_EQ(layer->paint_bounds(), child_intersect_bounds);
EXPECT_TRUE(mock_layer->needs_painting(paint_context()));
EXPECT_TRUE(layer->needs_painting(paint_context()));
EXPECT_EQ(mock_layer->parent_cull_rect(), intersect_bounds);
EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix);
EXPECT_EQ(mock_layer->parent_mutators(),
std::vector({Mutator(layer_bounds)}));
layer->Paint(paint_context());
EXPECT_EQ(
mock_canvas().draw_calls(),
std::vector(
{MockCanvas::DrawCall{0, MockCanvas::SaveData{1}},
MockCanvas::DrawCall{
1, MockCanvas::ClipRectData{layer_bounds, SkClipOp::kIntersect,
MockCanvas::kSoft_ClipEdgeStyle}},
MockCanvas::DrawCall{
1,
MockCanvas::SaveLayerData{layer_bounds, clip_paint, nullptr, 2}},
MockCanvas::DrawCall{
2, MockCanvas::DrawPathData{child_path, child_paint}},
MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}},
MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}}));
}
TEST_F(CheckerBoardLayerTest, ClipRectSaveLayerCheckBoard) {
const SkMatrix initial_matrix = SkMatrix::Translate(0.5f, 1.0f);
const SkRect cull_bounds = SkRect::MakeXYWH(0.0, 0.0, 2.0, 4.0);
const SkRect child_bounds = SkRect::MakeXYWH(2.5, 5.0, 4.5, 4.0);
const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
const SkPath child_path = SkPath().addRect(child_bounds);
const SkPaint child_paint = SkPaint(SkColors::kYellow);
const SkPaint clip_paint;
auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
auto layer = std::make_shared<ClipRectLayer>(layer_bounds,
Clip::antiAliasWithSaveLayer);
layer->Add(mock_layer);
SkRect intersect_bounds = layer_bounds;
SkRect child_intersect_bounds = layer_bounds;
intersect_bounds.intersect(cull_bounds);
child_intersect_bounds.intersect(child_bounds);
preroll_context()->cull_rect = cull_bounds; // Cull child
layer->Preroll(preroll_context(), initial_matrix);
EXPECT_EQ(preroll_context()->cull_rect, cull_bounds); // Untouched
EXPECT_TRUE(preroll_context()->mutators_stack.is_empty()); // Untouched
EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
EXPECT_EQ(layer->paint_bounds(), child_intersect_bounds);
EXPECT_TRUE(mock_layer->needs_painting(paint_context()));
EXPECT_TRUE(layer->needs_painting(paint_context()));
EXPECT_EQ(mock_layer->parent_cull_rect(), intersect_bounds);
EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix);
EXPECT_EQ(mock_layer->parent_mutators(),
std::vector({Mutator(layer_bounds)}));
layer->Paint(check_board_context());
EXPECT_NE(
mock_canvas().draw_calls(),
std::vector(
{MockCanvas::DrawCall{0, MockCanvas::SaveData{1}},
MockCanvas::DrawCall{
1, MockCanvas::ClipRectData{layer_bounds, SkClipOp::kIntersect,
MockCanvas::kSoft_ClipEdgeStyle}},
MockCanvas::DrawCall{
1,
MockCanvas::SaveLayerData{layer_bounds, clip_paint, nullptr, 2}},
MockCanvas::DrawCall{
2, MockCanvas::DrawPathData{child_path, child_paint}},
MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}},
MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}}));
}
TEST_F(CheckerBoardLayerTest, ClipPathSaveLayerNotCheckBoard) {
const SkMatrix initial_matrix = SkMatrix::Translate(0.5f, 1.0f);
const SkRect child_bounds = SkRect::MakeXYWH(1.0, 2.0, 2.0, 2.0);
const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
const SkPath child_path = SkPath().addRect(child_bounds);
const SkPath layer_path = SkPath().addRect(layer_bounds);
const SkPaint child_paint = SkPaint(SkColors::kYellow);
const SkPaint clip_paint;
auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
auto layer =
std::make_shared<ClipPathLayer>(layer_path, Clip::antiAliasWithSaveLayer);
layer->Add(mock_layer);
layer->Preroll(preroll_context(), initial_matrix);
EXPECT_EQ(preroll_context()->cull_rect, kGiantRect); // Untouched
EXPECT_TRUE(preroll_context()->mutators_stack.is_empty()); // Untouched
EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
EXPECT_EQ(layer->paint_bounds(), mock_layer->paint_bounds());
EXPECT_TRUE(mock_layer->needs_painting(paint_context()));
EXPECT_TRUE(layer->needs_painting(paint_context()));
EXPECT_EQ(mock_layer->parent_cull_rect(), layer_bounds);
EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix);
EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(layer_path)}));
layer->Paint(paint_context());
EXPECT_EQ(
mock_canvas().draw_calls(),
std::vector(
{MockCanvas::DrawCall{0, MockCanvas::SaveData{1}},
MockCanvas::DrawCall{
1, MockCanvas::ClipRectData{layer_bounds, SkClipOp::kIntersect,
MockCanvas::kSoft_ClipEdgeStyle}},
MockCanvas::DrawCall{
1,
MockCanvas::SaveLayerData{child_bounds, clip_paint, nullptr, 2}},
MockCanvas::DrawCall{
2, MockCanvas::DrawPathData{child_path, child_paint}},
MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}},
MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}}));
}
TEST_F(CheckerBoardLayerTest, ClipPathSaveLayerCheckBoard) {
const SkMatrix initial_matrix = SkMatrix::Translate(0.5f, 1.0f);
const SkRect child_bounds = SkRect::MakeXYWH(1.0, 2.0, 2.0, 2.0);
const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
const SkPath child_path = SkPath().addRect(child_bounds);
const SkPath layer_path = SkPath().addRect(layer_bounds);
const SkPaint child_paint = SkPaint(SkColors::kYellow);
const SkPaint clip_paint;
auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
auto layer =
std::make_shared<ClipPathLayer>(layer_path, Clip::antiAliasWithSaveLayer);
layer->Add(mock_layer);
layer->Preroll(preroll_context(), initial_matrix);
EXPECT_EQ(preroll_context()->cull_rect, kGiantRect); // Untouched
EXPECT_TRUE(preroll_context()->mutators_stack.is_empty()); // Untouched
EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
EXPECT_EQ(layer->paint_bounds(), mock_layer->paint_bounds());
EXPECT_TRUE(mock_layer->needs_painting(paint_context()));
EXPECT_TRUE(layer->needs_painting(paint_context()));
EXPECT_EQ(mock_layer->parent_cull_rect(), layer_bounds);
EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix);
EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(layer_path)}));
layer->Paint(check_board_context());
EXPECT_NE(
mock_canvas().draw_calls(),
std::vector(
{MockCanvas::DrawCall{0, MockCanvas::SaveData{1}},
MockCanvas::DrawCall{
1, MockCanvas::ClipRectData{layer_bounds, SkClipOp::kIntersect,
MockCanvas::kSoft_ClipEdgeStyle}},
MockCanvas::DrawCall{
1,
MockCanvas::SaveLayerData{child_bounds, clip_paint, nullptr, 2}},
MockCanvas::DrawCall{
2, MockCanvas::DrawPathData{child_path, child_paint}},
MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}},
MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}}));
}
TEST_F(CheckerBoardLayerTest, ClipRRectSaveLayerNotCheckBoard) {
const SkMatrix initial_matrix = SkMatrix::Translate(0.5f, 1.0f);
const SkRect child_bounds = SkRect::MakeXYWH(1.0, 2.0, 2.0, 2.0);
const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
const SkPath child_path = SkPath().addRect(child_bounds);
const SkRRect layer_rrect = SkRRect::MakeRect(layer_bounds);
const SkPaint child_paint = SkPaint(SkColors::kYellow);
const SkPaint clip_paint;
auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
auto layer = std::make_shared<ClipRRectLayer>(layer_rrect,
Clip::antiAliasWithSaveLayer);
layer->Add(mock_layer);
layer->Preroll(preroll_context(), initial_matrix);
EXPECT_EQ(preroll_context()->cull_rect, kGiantRect); // Untouched
EXPECT_TRUE(preroll_context()->mutators_stack.is_empty()); // Untouched
EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
EXPECT_EQ(layer->paint_bounds(), mock_layer->paint_bounds());
EXPECT_TRUE(mock_layer->needs_painting(paint_context()));
EXPECT_TRUE(layer->needs_painting(paint_context()));
EXPECT_EQ(mock_layer->parent_cull_rect(), layer_bounds);
EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix);
EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(layer_rrect)}));
layer->Paint(paint_context());
EXPECT_EQ(
mock_canvas().draw_calls(),
std::vector(
{MockCanvas::DrawCall{0, MockCanvas::SaveData{1}},
MockCanvas::DrawCall{
1, MockCanvas::ClipRectData{layer_bounds, SkClipOp::kIntersect,
MockCanvas::kSoft_ClipEdgeStyle}},
MockCanvas::DrawCall{
1,
MockCanvas::SaveLayerData{child_bounds, clip_paint, nullptr, 2}},
MockCanvas::DrawCall{
2, MockCanvas::DrawPathData{child_path, child_paint}},
MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}},
MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}}));
}
TEST_F(CheckerBoardLayerTest, ClipRRectSaveLayerCheckBoard) {
const SkMatrix initial_matrix = SkMatrix::Translate(0.5f, 1.0f);
const SkRect child_bounds = SkRect::MakeXYWH(1.0, 2.0, 2.0, 2.0);
const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
const SkPath child_path = SkPath().addRect(child_bounds);
const SkRRect layer_rrect = SkRRect::MakeRect(layer_bounds);
const SkPaint child_paint = SkPaint(SkColors::kYellow);
const SkPaint clip_paint;
auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
auto layer = std::make_shared<ClipRRectLayer>(layer_rrect,
Clip::antiAliasWithSaveLayer);
layer->Add(mock_layer);
layer->Preroll(preroll_context(), initial_matrix);
EXPECT_EQ(preroll_context()->cull_rect, kGiantRect); // Untouched
EXPECT_TRUE(preroll_context()->mutators_stack.is_empty()); // Untouched
EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
EXPECT_EQ(layer->paint_bounds(), mock_layer->paint_bounds());
EXPECT_TRUE(mock_layer->needs_painting(paint_context()));
EXPECT_TRUE(layer->needs_painting(paint_context()));
EXPECT_EQ(mock_layer->parent_cull_rect(), layer_bounds);
EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix);
EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(layer_rrect)}));
layer->Paint(check_board_context());
EXPECT_NE(
mock_canvas().draw_calls(),
std::vector(
{MockCanvas::DrawCall{0, MockCanvas::SaveData{1}},
MockCanvas::DrawCall{
1, MockCanvas::ClipRectData{layer_bounds, SkClipOp::kIntersect,
MockCanvas::kSoft_ClipEdgeStyle}},
MockCanvas::DrawCall{
1,
MockCanvas::SaveLayerData{child_bounds, clip_paint, nullptr, 2}},
MockCanvas::DrawCall{
2, MockCanvas::DrawPathData{child_path, child_paint}},
MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}},
MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}}));
}
TEST_F(CheckerBoardLayerTest, PhysicalSaveLayerNotCheckBoard) {
constexpr float initial_elevation = 20.0f;
SkPath layer_path;
layer_path.addRect(0, 0, 8, 8).close();
auto layer = std::make_shared<PhysicalShapeLayer>(
SK_ColorGREEN, SK_ColorBLACK, initial_elevation, layer_path,
Clip::antiAliasWithSaveLayer);
layer->Preroll(preroll_context(), SkMatrix());
// The Fuchsia system compositor handles all elevated PhysicalShapeLayers and
// their shadows , so we do not do any painting there.
EXPECT_EQ(layer->paint_bounds(),
PhysicalShapeLayer::ComputeShadowBounds(
layer_path, initial_elevation, 1.0f, SkMatrix()));
EXPECT_TRUE(layer->needs_painting(paint_context()));
EXPECT_EQ(layer->elevation(), initial_elevation);
const SkRect paint_bounds = SkRect::MakeXYWH(0, 0, 8, 8);
const SkPaint clip_paint;
SkPaint layer_paint;
layer_paint.setColor(SK_ColorGREEN);
layer_paint.setAntiAlias(true);
layer->Paint(paint_context());
EXPECT_EQ(
mock_canvas().draw_calls(),
std::vector(
{MockCanvas::DrawCall{0, MockCanvas::DrawShadowData{layer_path}},
MockCanvas::DrawCall{0, MockCanvas::SaveData{1}},
MockCanvas::DrawCall{
1, MockCanvas::ClipRectData{paint_bounds, SkClipOp::kIntersect,
MockCanvas::kSoft_ClipEdgeStyle}},
MockCanvas::DrawCall{
1, MockCanvas::SaveLayerData{layer->paint_bounds(), clip_paint,
nullptr, 2}},
MockCanvas::DrawCall{2, MockCanvas::DrawPaint{layer_paint}},
MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}},
MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}}));
}
TEST_F(CheckerBoardLayerTest, PhysicalSaveLayerCheckBoard) {
constexpr float initial_elevation = 20.0f;
SkPath layer_path;
layer_path.addRect(0, 0, 8, 8).close();
auto layer = std::make_shared<PhysicalShapeLayer>(
SK_ColorGREEN, SK_ColorBLACK, initial_elevation, layer_path,
Clip::antiAliasWithSaveLayer);
layer->Preroll(preroll_context(), SkMatrix());
// The Fuchsia system compositor handles all elevated PhysicalShapeLayers and
// their shadows , so we do not do any painting there.
EXPECT_EQ(layer->paint_bounds(),
PhysicalShapeLayer::ComputeShadowBounds(
layer_path, initial_elevation, 1.0f, SkMatrix()));
EXPECT_TRUE(layer->needs_painting(paint_context()));
EXPECT_EQ(layer->elevation(), initial_elevation);
const SkRect paint_bounds = SkRect::MakeXYWH(0, 0, 8, 8);
const SkPaint clip_paint;
SkPaint layer_paint;
layer_paint.setColor(SK_ColorGREEN);
layer_paint.setAntiAlias(true);
layer->Paint(check_board_context());
EXPECT_NE(
mock_canvas().draw_calls(),
std::vector(
{MockCanvas::DrawCall{0, MockCanvas::DrawShadowData{layer_path}},
MockCanvas::DrawCall{0, MockCanvas::SaveData{1}},
MockCanvas::DrawCall{
1, MockCanvas::ClipRectData{paint_bounds, SkClipOp::kIntersect,
MockCanvas::kSoft_ClipEdgeStyle}},
MockCanvas::DrawCall{
1, MockCanvas::SaveLayerData{layer->paint_bounds(), clip_paint,
nullptr, 2}},
MockCanvas::DrawCall{2, MockCanvas::DrawPaint{layer_paint}},
MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}},
MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}}));
}
#endif
} // namespace testing
} // namespace flutter