blob: d6903a75fa22e85ab54c65011f76f8be4eb76b79 [file] [log] [blame]
// Copyright 2016 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/platform/graphics/filters/fe_composite.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/graphics/filters/fe_offset.h"
#include "third_party/blink/renderer/platform/graphics/filters/filter.h"
#include "third_party/blink/renderer/platform/graphics/filters/source_graphic.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
namespace blink {
class FECompositeTest : public testing::Test {
protected:
FEComposite* CreateComposite(CompositeOperationType type,
float k1 = 0,
float k2 = 0,
float k3 = 0,
float k4 = 0) {
// Use big filter region to avoid it from affecting FEComposite's MapRect
// results.
FloatRect filter_region(-10000, -10000, 20000, 20000);
auto* filter = MakeGarbageCollected<Filter>(FloatRect(), filter_region, 1,
Filter::kUserSpace);
// Input 1 of composite has a fixed output rect.
auto* source_graphic1 = MakeGarbageCollected<SourceGraphic>(filter);
source_graphic1->SetClipsToBounds(false);
source_graphic1->SetSourceRectForTests(kInput1Rect);
// Input 2 of composite will pass composite->MapRect()'s parameter as its
// output.
auto* source_graphic2 = MakeGarbageCollected<SourceGraphic>(filter);
source_graphic2->SetClipsToBounds(false);
// Composite input 1 and input 2.
auto* composite =
MakeGarbageCollected<FEComposite>(filter, type, k1, k2, k3, k4);
composite->SetClipsToBounds(false);
composite->InputEffects().push_back(source_graphic1);
composite->InputEffects().push_back(source_graphic2);
return composite;
}
const IntRect kInput1Rect = {50, -50, 100, 100};
};
#define EXPECT_INTERSECTION(c) \
do { \
EXPECT_TRUE(c->MapRect(FloatRect()).IsEmpty()); \
EXPECT_TRUE(c->MapRect(FloatRect(0, 0, 50, 50)).IsEmpty()); \
EXPECT_EQ(FloatRect(50, 0, 100, 50), \
c->MapRect(FloatRect(0, 0, 200, 200))); \
} while (false)
#define EXPECT_INPUT1(c) \
do { \
EXPECT_EQ(FloatRect(kInput1Rect), c->MapRect(FloatRect())); \
EXPECT_EQ(FloatRect(kInput1Rect), c->MapRect(FloatRect(0, 0, 50, 50))); \
EXPECT_EQ(FloatRect(kInput1Rect), c->MapRect(FloatRect(0, 0, 200, 200))); \
} while (false)
#define EXPECT_INPUT2(c) \
do { \
EXPECT_TRUE(c->MapRect(FloatRect()).IsEmpty()); \
EXPECT_EQ(FloatRect(0, 0, 50, 50), c->MapRect(FloatRect(0, 0, 50, 50))); \
EXPECT_EQ(FloatRect(0, 0, 200, 200), \
c->MapRect(FloatRect(0, 0, 200, 200))); \
} while (false)
#define EXPECT_UNION(c) \
do { \
EXPECT_EQ(FloatRect(kInput1Rect), c->MapRect(FloatRect())); \
EXPECT_EQ(FloatRect(0, -50, 150, 100), \
c->MapRect(FloatRect(0, 0, 50, 50))); \
EXPECT_EQ(FloatRect(0, -50, 200, 250), \
c->MapRect(FloatRect(0, 0, 200, 200))); \
} while (false)
#define EXPECT_EMPTY(c) \
do { \
EXPECT_TRUE(c->MapRect(FloatRect()).IsEmpty()); \
EXPECT_TRUE(c->MapRect(FloatRect(0, 0, 50, 50)).IsEmpty()); \
EXPECT_TRUE(c->MapRect(FloatRect(0, 0, 200, 200)).IsEmpty()); \
} while (false)
TEST_F(FECompositeTest, MapRectIn) {
EXPECT_INTERSECTION(CreateComposite(FECOMPOSITE_OPERATOR_IN));
}
TEST_F(FECompositeTest, MapRectATop) {
EXPECT_INPUT2(CreateComposite(FECOMPOSITE_OPERATOR_ATOP));
}
TEST_F(FECompositeTest, MapRectOtherOperators) {
EXPECT_UNION(CreateComposite(FECOMPOSITE_OPERATOR_OVER));
EXPECT_UNION(CreateComposite(FECOMPOSITE_OPERATOR_OUT));
EXPECT_UNION(CreateComposite(FECOMPOSITE_OPERATOR_XOR));
EXPECT_UNION(CreateComposite(FECOMPOSITE_OPERATOR_LIGHTER));
}
TEST_F(FECompositeTest, MapRectArithmetic) {
EXPECT_EMPTY(CreateComposite(FECOMPOSITE_OPERATOR_ARITHMETIC, 0, 0, 0, 0));
EXPECT_UNION(CreateComposite(FECOMPOSITE_OPERATOR_ARITHMETIC, 0, 0, 0, 1));
EXPECT_INPUT2(CreateComposite(FECOMPOSITE_OPERATOR_ARITHMETIC, 0, 0, 1, 0));
EXPECT_UNION(CreateComposite(FECOMPOSITE_OPERATOR_ARITHMETIC, 0, 0, 1, 1));
EXPECT_INPUT1(CreateComposite(FECOMPOSITE_OPERATOR_ARITHMETIC, 0, 1, 0, 0));
EXPECT_UNION(CreateComposite(FECOMPOSITE_OPERATOR_ARITHMETIC, 0, 1, 0, 1));
EXPECT_UNION(CreateComposite(FECOMPOSITE_OPERATOR_ARITHMETIC, 0, 1, 1, 0));
EXPECT_UNION(CreateComposite(FECOMPOSITE_OPERATOR_ARITHMETIC, 0, 1, 1, 1));
EXPECT_INTERSECTION(
CreateComposite(FECOMPOSITE_OPERATOR_ARITHMETIC, 1, 0, 0, 0));
EXPECT_UNION(CreateComposite(FECOMPOSITE_OPERATOR_ARITHMETIC, 1, 0, 0, 1));
EXPECT_INPUT2(CreateComposite(FECOMPOSITE_OPERATOR_ARITHMETIC, 1, 0, 1, 0));
EXPECT_UNION(CreateComposite(FECOMPOSITE_OPERATOR_ARITHMETIC, 1, 0, 1, 1));
EXPECT_INPUT1(CreateComposite(FECOMPOSITE_OPERATOR_ARITHMETIC, 1, 1, 0, 0));
EXPECT_UNION(CreateComposite(FECOMPOSITE_OPERATOR_ARITHMETIC, 1, 1, 0, 1));
EXPECT_UNION(CreateComposite(FECOMPOSITE_OPERATOR_ARITHMETIC, 1, 1, 1, 0));
EXPECT_UNION(CreateComposite(FECOMPOSITE_OPERATOR_ARITHMETIC, 1, 1, 1, 1));
}
TEST_F(FECompositeTest, MapRectArithmeticK4Clipped) {
// Arithmetic operator with positive K4 will always affect the whole primitive
// subregion.
auto* c = CreateComposite(FECOMPOSITE_OPERATOR_ARITHMETIC, 1, 1, 1, 1);
c->SetClipsToBounds(true);
FloatRect bounds(222, 333, 444, 555);
c->SetFilterPrimitiveSubregion(bounds);
EXPECT_EQ(bounds, c->MapRect(FloatRect()));
EXPECT_EQ(bounds, c->MapRect(FloatRect(100, 200, 300, 400)));
}
} // namespace blink