blob: f4bc6c67e3b3b19db8b7b5947d1ebfe245e16823 [file] [log] [blame]
// Copyright 2014 The Chromium 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 "third_party/blink/renderer/core/paint/nine_piece_image_grid.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/css/css_gradient_value.h"
#include "third_party/blink/renderer/core/style/nine_piece_image.h"
#include "third_party/blink/renderer/core/style/style_generated_image.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
namespace blink {
namespace {
class NinePieceImageGridTest : public RenderingTest {
public:
NinePieceImageGridTest() = default;
StyleImage* GeneratedImage() {
cssvalue::CSSGradientValue* gradient =
cssvalue::CSSLinearGradientValue::Create(
nullptr, nullptr, nullptr, nullptr, nullptr, cssvalue::kRepeating);
return StyleGeneratedImage::Create(*gradient);
}
};
TEST_F(NinePieceImageGridTest, NinePieceImagePainting_NoDrawables) {
NinePieceImage nine_piece;
nine_piece.SetImage(GeneratedImage());
IntSize image_size(100, 100);
IntRect border_image_area(0, 0, 100, 100);
IntRectOutsets border_widths(0, 0, 0, 0);
NinePieceImageGrid grid = NinePieceImageGrid(
nine_piece, image_size, border_image_area, border_widths);
for (NinePiece piece = kMinPiece; piece < kMaxPiece; ++piece) {
NinePieceImageGrid::NinePieceDrawInfo draw_info =
grid.GetNinePieceDrawInfo(piece, 1);
EXPECT_FALSE(draw_info.is_drawable);
}
}
TEST_F(NinePieceImageGridTest, NinePieceImagePainting_AllDrawable) {
NinePieceImage nine_piece;
nine_piece.SetImage(GeneratedImage());
nine_piece.SetImageSlices(LengthBox(10, 10, 10, 10));
nine_piece.SetFill(true);
IntSize image_size(100, 100);
IntRect border_image_area(0, 0, 100, 100);
IntRectOutsets border_widths(10, 10, 10, 10);
NinePieceImageGrid grid = NinePieceImageGrid(
nine_piece, image_size, border_image_area, border_widths);
for (NinePiece piece = kMinPiece; piece < kMaxPiece; ++piece) {
NinePieceImageGrid::NinePieceDrawInfo draw_info =
grid.GetNinePieceDrawInfo(piece, 1);
EXPECT_TRUE(draw_info.is_drawable);
}
}
TEST_F(NinePieceImageGridTest, NinePieceImagePainting_NoFillMiddleNotDrawable) {
NinePieceImage nine_piece;
nine_piece.SetImage(GeneratedImage());
nine_piece.SetImageSlices(LengthBox(10, 10, 10, 10));
nine_piece.SetFill(false); // default
IntSize image_size(100, 100);
IntRect border_image_area(0, 0, 100, 100);
IntRectOutsets border_widths(10, 10, 10, 10);
NinePieceImageGrid grid = NinePieceImageGrid(
nine_piece, image_size, border_image_area, border_widths);
for (NinePiece piece = kMinPiece; piece < kMaxPiece; ++piece) {
NinePieceImageGrid::NinePieceDrawInfo draw_info =
grid.GetNinePieceDrawInfo(piece, 1);
if (piece != kMiddlePiece)
EXPECT_TRUE(draw_info.is_drawable);
else
EXPECT_FALSE(draw_info.is_drawable);
}
}
TEST_F(NinePieceImageGridTest, NinePieceImagePainting_TopLeftDrawable) {
NinePieceImage nine_piece;
nine_piece.SetImage(GeneratedImage());
nine_piece.SetImageSlices(LengthBox(10, 10, 10, 10));
IntSize image_size(100, 100);
IntRect border_image_area(0, 0, 100, 100);
const struct {
IntRectOutsets border_widths;
bool expected_is_drawable;
} test_cases[] = {
{IntRectOutsets(0, 0, 0, 0), false},
{IntRectOutsets(10, 0, 0, 0), false},
{IntRectOutsets(0, 0, 0, 10), false},
{IntRectOutsets(10, 0, 0, 10), true},
};
for (const auto& test_case : test_cases) {
NinePieceImageGrid grid = NinePieceImageGrid(
nine_piece, image_size, border_image_area, test_case.border_widths);
for (NinePiece piece = kMinPiece; piece < kMaxPiece; ++piece) {
NinePieceImageGrid::NinePieceDrawInfo draw_info =
grid.GetNinePieceDrawInfo(piece, 1);
if (piece == kTopLeftPiece)
EXPECT_EQ(draw_info.is_drawable, test_case.expected_is_drawable);
}
}
}
TEST_F(NinePieceImageGridTest, NinePieceImagePainting_ScaleDownBorder) {
NinePieceImage nine_piece;
nine_piece.SetImage(GeneratedImage());
nine_piece.SetImageSlices(LengthBox(10, 10, 10, 10));
IntSize image_size(100, 100);
IntRect border_image_area(0, 0, 100, 100);
IntRectOutsets border_widths(10, 10, 10, 10);
// Set border slices wide enough so that the widths are scaled
// down and corner pieces cover the entire border image area.
nine_piece.SetBorderSlices(BorderImageLengthBox(6));
NinePieceImageGrid grid = NinePieceImageGrid(
nine_piece, image_size, border_image_area, border_widths);
for (NinePiece piece = kMinPiece; piece < kMaxPiece; ++piece) {
NinePieceImageGrid::NinePieceDrawInfo draw_info =
grid.GetNinePieceDrawInfo(piece, 1);
if (draw_info.is_corner_piece)
EXPECT_EQ(draw_info.destination.Size(), FloatSize(50, 50));
else
EXPECT_TRUE(draw_info.destination.Size().IsEmpty());
}
}
TEST_F(NinePieceImageGridTest, NinePieceImagePainting) {
const struct {
IntSize image_size;
IntRect border_image_area;
IntRectOutsets border_widths;
bool fill;
LengthBox image_slices;
Image::TileRule horizontal_rule;
Image::TileRule vertical_rule;
struct {
bool is_drawable;
bool is_corner_piece;
FloatRect destination;
FloatRect source;
float tile_scale_horizontal;
float tile_scale_vertical;
Image::TileRule horizontal_rule;
Image::TileRule vertical_rule;
} pieces[9];
} test_cases[] = {
{// Empty border and slices but with fill
IntSize(100, 100),
IntRect(0, 0, 100, 100),
IntRectOutsets(0, 0, 0, 0),
true,
LengthBox(Length(0, kFixed), Length(0, kFixed), Length(0, kFixed),
Length(0, kFixed)),
Image::kStretchTile,
Image::kStretchTile,
{
{false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
Image::kStretchTile, Image::kStretchTile},
{false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
Image::kStretchTile, Image::kStretchTile},
{false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
Image::kStretchTile, Image::kStretchTile},
{false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
Image::kStretchTile, Image::kStretchTile},
{false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
Image::kStretchTile, Image::kStretchTile},
{false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
Image::kStretchTile, Image::kStretchTile},
{false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
Image::kStretchTile, Image::kStretchTile},
{false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
Image::kStretchTile, Image::kStretchTile},
{true, false, FloatRect(0, 0, 100, 100), FloatRect(0, 0, 100, 100),
1, 1, Image::kStretchTile, Image::kStretchTile},
}},
{// Single border and fill
IntSize(100, 100),
IntRect(0, 0, 100, 100),
IntRectOutsets(0, 0, 10, 0),
true,
LengthBox(Length(20, kPercent), Length(20, kPercent),
Length(20, kPercent), Length(20, kPercent)),
Image::kStretchTile,
Image::kStretchTile,
{
{false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
Image::kStretchTile, Image::kStretchTile},
{false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
Image::kStretchTile, Image::kStretchTile},
{false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
Image::kStretchTile, Image::kStretchTile},
{false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
Image::kStretchTile, Image::kStretchTile},
{false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
Image::kStretchTile, Image::kStretchTile},
{false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
Image::kStretchTile, Image::kStretchTile},
{false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
Image::kStretchTile, Image::kStretchTile},
{true, false, FloatRect(0, 90, 100, 10), FloatRect(20, 80, 60, 20),
0.5, 0.5, Image::kStretchTile, Image::kStretchTile},
{true, false, FloatRect(0, 0, 100, 90), FloatRect(20, 20, 60, 60),
1.666667, 1.5, Image::kStretchTile, Image::kStretchTile},
}},
{// All borders, no fill
IntSize(100, 100),
IntRect(0, 0, 100, 100),
IntRectOutsets(10, 10, 10, 10),
false,
LengthBox(Length(20, kPercent), Length(20, kPercent),
Length(20, kPercent), Length(20, kPercent)),
Image::kStretchTile,
Image::kStretchTile,
{
{true, true, FloatRect(0, 0, 10, 10), FloatRect(0, 0, 20, 20), 1, 1,
Image::kStretchTile, Image::kStretchTile},
{true, true, FloatRect(0, 90, 10, 10), FloatRect(0, 80, 20, 20), 1,
1, Image::kStretchTile, Image::kStretchTile},
{true, false, FloatRect(0, 10, 10, 80), FloatRect(0, 20, 20, 60),
0.5, 0.5, Image::kStretchTile, Image::kStretchTile},
{true, true, FloatRect(90, 0, 10, 10), FloatRect(80, 0, 20, 20), 1,
1, Image::kStretchTile, Image::kStretchTile},
{true, true, FloatRect(90, 90, 10, 10), FloatRect(80, 80, 20, 20), 1,
1, Image::kStretchTile, Image::kStretchTile},
{true, false, FloatRect(90, 10, 10, 80), FloatRect(80, 20, 20, 60),
0.5, 0.5, Image::kStretchTile, Image::kStretchTile},
{true, false, FloatRect(10, 0, 80, 10), FloatRect(20, 0, 60, 20),
0.5, 0.5, Image::kStretchTile, Image::kStretchTile},
{true, false, FloatRect(10, 90, 80, 10), FloatRect(20, 80, 60, 20),
0.5, 0.5, Image::kStretchTile, Image::kStretchTile},
{false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
Image::kStretchTile, Image::kStretchTile},
}},
{// Single border, no fill
IntSize(100, 100),
IntRect(0, 0, 100, 100),
IntRectOutsets(0, 0, 0, 10),
false,
LengthBox(Length(20, kPercent), Length(20, kPercent),
Length(20, kPercent), Length(20, kPercent)),
Image::kStretchTile,
Image::kRoundTile,
{
{false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
Image::kStretchTile, Image::kStretchTile},
{false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
Image::kStretchTile, Image::kStretchTile},
{true, false, FloatRect(0, 0, 10, 100), FloatRect(0, 20, 20, 60),
0.5, 0.5, Image::kStretchTile, Image::kRoundTile},
{false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
Image::kStretchTile, Image::kStretchTile},
{false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
Image::kStretchTile, Image::kStretchTile},
{false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
Image::kStretchTile, Image::kRoundTile},
{false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
Image::kStretchTile, Image::kRoundTile},
{false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
Image::kStretchTile, Image::kRoundTile},
{false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
Image::kStretchTile, Image::kRoundTile},
}},
{// All borders but no slices, with fill (stretch horizontally, space
// vertically)
IntSize(100, 100),
IntRect(0, 0, 100, 100),
IntRectOutsets(10, 10, 10, 10),
true,
LengthBox(Length(0, kFixed), Length(0, kFixed), Length(0, kFixed),
Length(0, kFixed)),
Image::kStretchTile,
Image::kSpaceTile,
{
{false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
Image::kStretchTile, Image::kStretchTile},
{false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
Image::kStretchTile, Image::kStretchTile},
{false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
Image::kStretchTile, Image::kSpaceTile},
{false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
Image::kStretchTile, Image::kStretchTile},
{false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
Image::kStretchTile, Image::kStretchTile},
{false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
Image::kStretchTile, Image::kSpaceTile},
{false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
Image::kStretchTile, Image::kSpaceTile},
{false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
Image::kStretchTile, Image::kSpaceTile},
{true, false, FloatRect(10, 10, 80, 80), FloatRect(0, 0, 100, 100),
0.800000, 1, Image::kStretchTile, Image::kSpaceTile},
}},
};
for (auto& test_case : test_cases) {
NinePieceImage nine_piece;
nine_piece.SetImage(GeneratedImage());
nine_piece.SetFill(test_case.fill);
nine_piece.SetImageSlices(test_case.image_slices);
nine_piece.SetHorizontalRule(
(ENinePieceImageRule)test_case.horizontal_rule);
nine_piece.SetVerticalRule((ENinePieceImageRule)test_case.vertical_rule);
NinePieceImageGrid grid = NinePieceImageGrid(
nine_piece, test_case.image_size, test_case.border_image_area,
test_case.border_widths);
for (NinePiece piece = kMinPiece; piece < kMaxPiece; ++piece) {
NinePieceImageGrid::NinePieceDrawInfo draw_info =
grid.GetNinePieceDrawInfo(piece, 1);
EXPECT_EQ(test_case.pieces[piece].is_drawable, draw_info.is_drawable);
if (!test_case.pieces[piece].is_drawable)
continue;
EXPECT_EQ(test_case.pieces[piece].destination.X(),
draw_info.destination.X());
EXPECT_EQ(test_case.pieces[piece].destination.Y(),
draw_info.destination.Y());
EXPECT_EQ(test_case.pieces[piece].destination.Width(),
draw_info.destination.Width());
EXPECT_EQ(test_case.pieces[piece].destination.Height(),
draw_info.destination.Height());
EXPECT_EQ(test_case.pieces[piece].source.X(), draw_info.source.X());
EXPECT_EQ(test_case.pieces[piece].source.Y(), draw_info.source.Y());
EXPECT_EQ(test_case.pieces[piece].source.Width(),
draw_info.source.Width());
EXPECT_EQ(test_case.pieces[piece].source.Height(),
draw_info.source.Height());
if (test_case.pieces[piece].is_corner_piece)
continue;
EXPECT_FLOAT_EQ(test_case.pieces[piece].tile_scale_horizontal,
draw_info.tile_scale.Width());
EXPECT_FLOAT_EQ(test_case.pieces[piece].tile_scale_vertical,
draw_info.tile_scale.Height());
EXPECT_EQ(test_case.pieces[piece].horizontal_rule,
draw_info.tile_rule.horizontal);
EXPECT_EQ(test_case.pieces[piece].vertical_rule,
draw_info.tile_rule.vertical);
}
}
}
} // namespace
} // namespace blink