blob: 6db33934f9db820933be5681ca9f0ea0f38ad7ae [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 "core/paint/NinePieceImageGrid.h"
#include "core/css/CSSGradientValue.h"
#include "core/layout/LayoutTestHelper.h"
#include "core/style/ComputedStyle.h"
#include "core/style/NinePieceImage.h"
#include "core/style/StyleGeneratedImage.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace blink {
namespace {
class NinePieceImageGridTest : public RenderingTest {
public:
NinePieceImageGridTest() {}
StyleImage* generatedImage() {
CSSLinearGradientValue* gradient =
CSSLinearGradientValue::create(Repeating);
return StyleGeneratedImage::create(*gradient);
}
private:
void SetUp() override { RenderingTest::SetUp(); }
};
TEST_F(NinePieceImageGridTest, NinePieceImagePainting_NoDrawables) {
NinePieceImage ninePiece;
ninePiece.setImage(generatedImage());
IntSize imageSize(100, 100);
IntRect borderImageArea(0, 0, 100, 100);
IntRectOutsets borderWidths(0, 0, 0, 0);
NinePieceImageGrid grid =
NinePieceImageGrid(ninePiece, imageSize, borderImageArea, borderWidths);
for (NinePiece piece = MinPiece; piece < MaxPiece; ++piece) {
NinePieceImageGrid::NinePieceDrawInfo drawInfo =
grid.getNinePieceDrawInfo(piece, 1);
EXPECT_FALSE(drawInfo.isDrawable);
}
}
TEST_F(NinePieceImageGridTest, NinePieceImagePainting_AllDrawable) {
NinePieceImage ninePiece;
ninePiece.setImage(generatedImage());
ninePiece.setImageSlices(LengthBox(10, 10, 10, 10));
ninePiece.setFill(true);
IntSize imageSize(100, 100);
IntRect borderImageArea(0, 0, 100, 100);
IntRectOutsets borderWidths(10, 10, 10, 10);
NinePieceImageGrid grid =
NinePieceImageGrid(ninePiece, imageSize, borderImageArea, borderWidths);
for (NinePiece piece = MinPiece; piece < MaxPiece; ++piece) {
NinePieceImageGrid::NinePieceDrawInfo drawInfo =
grid.getNinePieceDrawInfo(piece, 1);
EXPECT_TRUE(drawInfo.isDrawable);
}
}
TEST_F(NinePieceImageGridTest, NinePieceImagePainting_NoFillMiddleNotDrawable) {
NinePieceImage ninePiece;
ninePiece.setImage(generatedImage());
ninePiece.setImageSlices(LengthBox(10, 10, 10, 10));
ninePiece.setFill(false); // default
IntSize imageSize(100, 100);
IntRect borderImageArea(0, 0, 100, 100);
IntRectOutsets borderWidths(10, 10, 10, 10);
NinePieceImageGrid grid =
NinePieceImageGrid(ninePiece, imageSize, borderImageArea, borderWidths);
for (NinePiece piece = MinPiece; piece < MaxPiece; ++piece) {
NinePieceImageGrid::NinePieceDrawInfo drawInfo =
grid.getNinePieceDrawInfo(piece, 1);
if (piece != MiddlePiece)
EXPECT_TRUE(drawInfo.isDrawable);
else
EXPECT_FALSE(drawInfo.isDrawable);
}
}
TEST_F(NinePieceImageGridTest, NinePieceImagePainting_TopLeftDrawable) {
NinePieceImage ninePiece;
ninePiece.setImage(generatedImage());
ninePiece.setImageSlices(LengthBox(10, 10, 10, 10));
IntSize imageSize(100, 100);
IntRect borderImageArea(0, 0, 100, 100);
IntRectOutsets borderWidths(10, 10, 10, 10);
const struct {
IntRectOutsets borderWidths;
bool expectedIsDrawable;
} testCases[] = {
{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& testCase : testCases) {
NinePieceImageGrid grid = NinePieceImageGrid(
ninePiece, imageSize, borderImageArea, testCase.borderWidths);
for (NinePiece piece = MinPiece; piece < MaxPiece; ++piece) {
NinePieceImageGrid::NinePieceDrawInfo drawInfo =
grid.getNinePieceDrawInfo(piece, 1);
if (piece == TopLeftPiece)
EXPECT_EQ(drawInfo.isDrawable, testCase.expectedIsDrawable);
}
}
}
TEST_F(NinePieceImageGridTest, NinePieceImagePainting_ScaleDownBorder) {
NinePieceImage ninePiece;
ninePiece.setImage(generatedImage());
ninePiece.setImageSlices(LengthBox(10, 10, 10, 10));
IntSize imageSize(100, 100);
IntRect borderImageArea(0, 0, 100, 100);
IntRectOutsets borderWidths(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.
ninePiece.setBorderSlices(BorderImageLengthBox(6));
NinePieceImageGrid grid =
NinePieceImageGrid(ninePiece, imageSize, borderImageArea, borderWidths);
for (NinePiece piece = MinPiece; piece < MaxPiece; ++piece) {
NinePieceImageGrid::NinePieceDrawInfo drawInfo =
grid.getNinePieceDrawInfo(piece, 1);
if (drawInfo.isCornerPiece)
EXPECT_EQ(drawInfo.destination.size(), FloatSize(50, 50));
else
EXPECT_TRUE(drawInfo.destination.size().isEmpty());
}
}
TEST_F(NinePieceImageGridTest, NinePieceImagePainting) {
const struct {
IntSize imageSize;
IntRect borderImageArea;
IntRectOutsets borderWidths;
bool fill;
LengthBox imageSlices;
Image::TileRule horizontalRule;
Image::TileRule verticalRule;
struct {
bool isDrawable;
bool isCornerPiece;
FloatRect destination;
FloatRect source;
float tileScaleHorizontal;
float tileScaleVertical;
Image::TileRule horizontalRule;
Image::TileRule verticalRule;
} pieces[9];
} testCases[] = {
{// Empty border and slices but with fill
IntSize(100, 100),
IntRect(0, 0, 100, 100),
IntRectOutsets(0, 0, 0, 0),
true,
LengthBox(Length(0, Fixed), Length(0, Fixed), Length(0, Fixed),
Length(0, Fixed)),
Image::StretchTile,
Image::StretchTile,
{
{false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
Image::StretchTile, Image::StretchTile},
{false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
Image::StretchTile, Image::StretchTile},
{false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
Image::StretchTile, Image::StretchTile},
{false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
Image::StretchTile, Image::StretchTile},
{false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
Image::StretchTile, Image::StretchTile},
{false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
Image::StretchTile, Image::StretchTile},
{false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
Image::StretchTile, Image::StretchTile},
{false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
Image::StretchTile, Image::StretchTile},
{true, false, FloatRect(0, 0, 100, 100), FloatRect(0, 0, 100, 100),
1, 1, Image::StretchTile, Image::StretchTile},
}},
{// Single border and fill
IntSize(100, 100),
IntRect(0, 0, 100, 100),
IntRectOutsets(0, 0, 10, 0),
true,
LengthBox(Length(20, Percent), Length(20, Percent), Length(20, Percent),
Length(20, Percent)),
Image::StretchTile,
Image::StretchTile,
{
{false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
Image::StretchTile, Image::StretchTile},
{false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
Image::StretchTile, Image::StretchTile},
{false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
Image::StretchTile, Image::StretchTile},
{false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
Image::StretchTile, Image::StretchTile},
{false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
Image::StretchTile, Image::StretchTile},
{false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
Image::StretchTile, Image::StretchTile},
{false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
Image::StretchTile, Image::StretchTile},
{true, false, FloatRect(0, 90, 100, 10), FloatRect(20, 80, 60, 20),
0.5, 0.5, Image::StretchTile, Image::StretchTile},
{true, false, FloatRect(0, 0, 100, 90), FloatRect(20, 20, 60, 60),
1.666667, 1.5, Image::StretchTile, Image::StretchTile},
}},
{// All borders, no fill
IntSize(100, 100),
IntRect(0, 0, 100, 100),
IntRectOutsets(10, 10, 10, 10),
false,
LengthBox(Length(20, Percent), Length(20, Percent), Length(20, Percent),
Length(20, Percent)),
Image::StretchTile,
Image::StretchTile,
{
{true, true, FloatRect(0, 0, 10, 10), FloatRect(0, 0, 20, 20), 1, 1,
Image::StretchTile, Image::StretchTile},
{true, true, FloatRect(0, 90, 10, 10), FloatRect(0, 80, 20, 20), 1,
1, Image::StretchTile, Image::StretchTile},
{true, false, FloatRect(0, 10, 10, 80), FloatRect(0, 20, 20, 60),
0.5, 0.5, Image::StretchTile, Image::StretchTile},
{true, true, FloatRect(90, 0, 10, 10), FloatRect(80, 0, 20, 20), 1,
1, Image::StretchTile, Image::StretchTile},
{true, true, FloatRect(90, 90, 10, 10), FloatRect(80, 80, 20, 20), 1,
1, Image::StretchTile, Image::StretchTile},
{true, false, FloatRect(90, 10, 10, 80), FloatRect(80, 20, 20, 60),
0.5, 0.5, Image::StretchTile, Image::StretchTile},
{true, false, FloatRect(10, 0, 80, 10), FloatRect(20, 0, 60, 20),
0.5, 0.5, Image::StretchTile, Image::StretchTile},
{true, false, FloatRect(10, 90, 80, 10), FloatRect(20, 80, 60, 20),
0.5, 0.5, Image::StretchTile, Image::StretchTile},
{false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
Image::StretchTile, Image::StretchTile},
}},
{// Single border, no fill
IntSize(100, 100),
IntRect(0, 0, 100, 100),
IntRectOutsets(0, 0, 0, 10),
false,
LengthBox(Length(20, Percent), Length(20, Percent), Length(20, Percent),
Length(20, Percent)),
Image::StretchTile,
Image::RoundTile,
{
{false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
Image::StretchTile, Image::StretchTile},
{false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
Image::StretchTile, Image::StretchTile},
{true, false, FloatRect(0, 0, 10, 100), FloatRect(0, 20, 20, 60),
0.5, 0.5, Image::StretchTile, Image::RoundTile},
{false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
Image::StretchTile, Image::StretchTile},
{false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
Image::StretchTile, Image::StretchTile},
{false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
Image::StretchTile, Image::RoundTile},
{false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
Image::StretchTile, Image::RoundTile},
{false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
Image::StretchTile, Image::RoundTile},
{false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
Image::StretchTile, Image::RoundTile},
}},
{// 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, Fixed), Length(0, Fixed), Length(0, Fixed),
Length(0, Fixed)),
Image::StretchTile,
Image::SpaceTile,
{
{false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
Image::StretchTile, Image::StretchTile},
{false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
Image::StretchTile, Image::StretchTile},
{false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
Image::StretchTile, Image::SpaceTile},
{false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
Image::StretchTile, Image::StretchTile},
{false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
Image::StretchTile, Image::StretchTile},
{false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
Image::StretchTile, Image::SpaceTile},
{false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
Image::StretchTile, Image::SpaceTile},
{false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
Image::StretchTile, Image::SpaceTile},
{true, false, FloatRect(10, 10, 80, 80), FloatRect(0, 0, 100, 100),
0.800000, 1, Image::StretchTile, Image::SpaceTile},
}},
};
for (auto& testCase : testCases) {
NinePieceImage ninePiece;
ninePiece.setImage(generatedImage());
ninePiece.setFill(testCase.fill);
ninePiece.setImageSlices(testCase.imageSlices);
ninePiece.setHorizontalRule((ENinePieceImageRule)testCase.horizontalRule);
ninePiece.setVerticalRule((ENinePieceImageRule)testCase.verticalRule);
NinePieceImageGrid grid =
NinePieceImageGrid(ninePiece, testCase.imageSize,
testCase.borderImageArea, testCase.borderWidths);
for (NinePiece piece = MinPiece; piece < MaxPiece; ++piece) {
NinePieceImageGrid::NinePieceDrawInfo drawInfo =
grid.getNinePieceDrawInfo(piece, 1);
EXPECT_EQ(testCase.pieces[piece].isDrawable, drawInfo.isDrawable);
if (!testCase.pieces[piece].isDrawable)
continue;
EXPECT_EQ(testCase.pieces[piece].destination.x(),
drawInfo.destination.x());
EXPECT_EQ(testCase.pieces[piece].destination.y(),
drawInfo.destination.y());
EXPECT_EQ(testCase.pieces[piece].destination.width(),
drawInfo.destination.width());
EXPECT_EQ(testCase.pieces[piece].destination.height(),
drawInfo.destination.height());
EXPECT_EQ(testCase.pieces[piece].source.x(), drawInfo.source.x());
EXPECT_EQ(testCase.pieces[piece].source.y(), drawInfo.source.y());
EXPECT_EQ(testCase.pieces[piece].source.width(), drawInfo.source.width());
EXPECT_EQ(testCase.pieces[piece].source.height(),
drawInfo.source.height());
if (testCase.pieces[piece].isCornerPiece)
continue;
EXPECT_FLOAT_EQ(testCase.pieces[piece].tileScaleHorizontal,
drawInfo.tileScale.width());
EXPECT_FLOAT_EQ(testCase.pieces[piece].tileScaleVertical,
drawInfo.tileScale.height());
EXPECT_EQ(testCase.pieces[piece].horizontalRule,
drawInfo.tileRule.horizontal);
EXPECT_EQ(testCase.pieces[piece].verticalRule,
drawInfo.tileRule.vertical);
}
}
}
} // namespace
} // namespace blink