63136afbd0
Change-Id: Idc25109a598caabf01e3ab61dc97f984ff453d40 Reviewed-on: https://skia-review.googlesource.com/c/191664 Commit-Queue: Mike Reed <reed@google.com> Auto-Submit: Florin Malita <fmalita@chromium.org> Reviewed-by: Mike Reed <reed@google.com>
350 lines
12 KiB
C++
350 lines
12 KiB
C++
/*
|
|
* Copyright 2011 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#include "SkTypes.h"
|
|
|
|
#if !defined(SK_BUILD_FOR_GOOGLE3)
|
|
|
|
#include "SkRect.h"
|
|
#include "SkRectPriv.h"
|
|
#include "SkSGColor.h"
|
|
#include "SkSGDraw.h"
|
|
#include "SkSGGroup.h"
|
|
#include "SkSGInvalidationController.h"
|
|
#include "SkSGRect.h"
|
|
#include "SkSGRenderEffect.h"
|
|
#include "SkSGTransform.h"
|
|
#include "SkTo.h"
|
|
|
|
#include "Test.h"
|
|
|
|
#include <vector>
|
|
|
|
static void check_inval(skiatest::Reporter* reporter, const sk_sp<sksg::Node>& root,
|
|
const SkRect& expected_bounds,
|
|
const SkRect& expected_inval_bounds,
|
|
const std::vector<SkRect>* expected_damage) {
|
|
sksg::InvalidationController ic;
|
|
const auto bbox = root->revalidate(&ic, SkMatrix::I());
|
|
|
|
if (0) {
|
|
SkDebugf("** bbox: [%f %f %f %f], ibbox: [%f %f %f %f]\n",
|
|
bbox.fLeft, bbox.fTop, bbox.fRight, bbox.fBottom,
|
|
ic.bounds().left(), ic.bounds().top(), ic.bounds().right(), ic.bounds().bottom());
|
|
}
|
|
|
|
REPORTER_ASSERT(reporter, bbox == expected_bounds);
|
|
REPORTER_ASSERT(reporter, ic.bounds() == expected_inval_bounds);
|
|
|
|
if (expected_damage) {
|
|
const auto damage_count = SkTo<size_t>(ic.end() - ic.begin());
|
|
REPORTER_ASSERT(reporter, expected_damage->size() == damage_count);
|
|
for (size_t i = 0; i < std::min(expected_damage->size(), damage_count); ++i) {
|
|
const auto r1 = (*expected_damage)[i],
|
|
r2 = ic.begin()[i];
|
|
if (0) {
|
|
SkDebugf("*** expected inval: [%f %f %f %f], actual: [%f %f %f %f]\n",
|
|
r1.left(), r1.top(), r1.right(), r1.bottom(),
|
|
r2.left(), r2.top(), r2.right(), r2.bottom());
|
|
}
|
|
REPORTER_ASSERT(reporter, r1 == r2);
|
|
}
|
|
}
|
|
}
|
|
|
|
struct HitTest {
|
|
const SkPoint pt;
|
|
sk_sp<sksg::RenderNode> node;
|
|
};
|
|
|
|
static void check_hittest(skiatest::Reporter* reporter, const sk_sp<sksg::RenderNode>& root,
|
|
const std::vector<HitTest>& tests) {
|
|
for (const auto& tst : tests) {
|
|
const auto* node = root->nodeAt(tst.pt);
|
|
if (node != tst.node.get()) {
|
|
SkDebugf("*** nodeAt(%f, %f) - expected %p, got %p\n",
|
|
tst.pt.x(), tst.pt.y(), tst.node.get(), node);
|
|
}
|
|
REPORTER_ASSERT(reporter, tst.node.get() == node);
|
|
}
|
|
}
|
|
|
|
static void inval_test1(skiatest::Reporter* reporter) {
|
|
auto color = sksg::Color::Make(0xff000000);
|
|
auto r1 = sksg::Rect::Make(SkRect::MakeWH(100, 100)),
|
|
r2 = sksg::Rect::Make(SkRect::MakeWH(100, 100));
|
|
auto grp = sksg::Group::Make();
|
|
auto matrix = sksg::Matrix<SkMatrix>::Make(SkMatrix::I());
|
|
auto root = sksg::TransformEffect::Make(grp, matrix);
|
|
auto d1 = sksg::Draw::Make(r1, color),
|
|
d2 = sksg::Draw::Make(r2, color);
|
|
|
|
grp->addChild(d1);
|
|
grp->addChild(d2);
|
|
|
|
{
|
|
// Initial revalidation.
|
|
check_inval(reporter, root,
|
|
SkRect::MakeWH(100, 100),
|
|
SkRectPriv::MakeLargeS32(),
|
|
nullptr);
|
|
|
|
check_hittest(reporter, root, {
|
|
{{ -1, 0 }, nullptr },
|
|
{{ 0, -1 }, nullptr },
|
|
{{ 100, 0 }, nullptr },
|
|
{{ 0, 100 }, nullptr },
|
|
{{ 0, 0 }, d2 },
|
|
{{ 99, 99 }, d2 },
|
|
});
|
|
}
|
|
|
|
{
|
|
// Move r2 to (200 100).
|
|
r2->setL(200); r2->setT(100); r2->setR(300); r2->setB(200);
|
|
std::vector<SkRect> damage = { {0, 0, 100, 100}, { 200, 100, 300, 200} };
|
|
check_inval(reporter, root,
|
|
SkRect::MakeWH(300, 200),
|
|
SkRect::MakeWH(300, 200),
|
|
&damage);
|
|
|
|
check_hittest(reporter, root, {
|
|
{{ -1, 0 }, nullptr },
|
|
{{ 0, -1 }, nullptr },
|
|
{{ 100, 0 }, nullptr },
|
|
{{ 0, 100 }, nullptr },
|
|
{{ 0, 0 }, d1 },
|
|
{{ 99, 99 }, d1 },
|
|
|
|
{{ 199, 100 }, nullptr },
|
|
{{ 200, 99 }, nullptr },
|
|
{{ 300, 100 }, nullptr },
|
|
{{ 200, 200 }, nullptr },
|
|
{{ 200, 100 }, d2 },
|
|
{{ 299, 199 }, d2 },
|
|
});
|
|
}
|
|
|
|
{
|
|
// Update the common color.
|
|
color->setColor(0xffff0000);
|
|
std::vector<SkRect> damage = { {0, 0, 100, 100}, { 200, 100, 300, 200} };
|
|
check_inval(reporter, root,
|
|
SkRect::MakeWH(300, 200),
|
|
SkRect::MakeWH(300, 200),
|
|
&damage);
|
|
}
|
|
|
|
{
|
|
// Shrink r1.
|
|
r1->setR(50);
|
|
std::vector<SkRect> damage = { {0, 0, 100, 100}, { 0, 0, 50, 100} };
|
|
check_inval(reporter, root,
|
|
SkRect::MakeWH(300, 200),
|
|
SkRect::MakeWH(100, 100),
|
|
&damage);
|
|
|
|
check_hittest(reporter, root, {
|
|
{{ -1, 0 }, nullptr },
|
|
{{ 0, -1 }, nullptr },
|
|
{{ 50, 0 }, nullptr },
|
|
{{ 0, 100 }, nullptr },
|
|
{{ 0, 0 }, d1 },
|
|
{{ 49, 99 }, d1 },
|
|
|
|
{{ 199, 100 }, nullptr },
|
|
{{ 200, 99 }, nullptr },
|
|
{{ 300, 100 }, nullptr },
|
|
{{ 200, 200 }, nullptr },
|
|
{{ 200, 100 }, d2 },
|
|
{{ 299, 199 }, d2 },
|
|
});
|
|
}
|
|
|
|
{
|
|
// Update transform.
|
|
matrix->setMatrix(SkMatrix::MakeScale(2, 2));
|
|
std::vector<SkRect> damage = { {0, 0, 300, 200}, { 0, 0, 600, 400} };
|
|
check_inval(reporter, root,
|
|
SkRect::MakeWH(600, 400),
|
|
SkRect::MakeWH(600, 400),
|
|
&damage);
|
|
|
|
check_hittest(reporter, root, {
|
|
{{ -1, 0 }, nullptr },
|
|
{{ 0, -1 }, nullptr },
|
|
{{ 25, 0 }, nullptr },
|
|
{{ 0, 50 }, nullptr },
|
|
{{ 0, 0 }, d1 },
|
|
{{ 24, 49 }, d1 },
|
|
|
|
{{ 99, 50 }, nullptr },
|
|
{{ 100, 49 }, nullptr },
|
|
{{ 150, 50 }, nullptr },
|
|
{{ 100, 100 }, nullptr },
|
|
{{ 100, 50 }, d2 },
|
|
{{ 149, 99 }, d2 },
|
|
});
|
|
}
|
|
|
|
{
|
|
// Shrink r2 under transform.
|
|
r2->setR(250);
|
|
std::vector<SkRect> damage = { {400, 200, 600, 400}, { 400, 200, 500, 400} };
|
|
check_inval(reporter, root,
|
|
SkRect::MakeWH(500, 400),
|
|
SkRect::MakeLTRB(400, 200, 600, 400),
|
|
&damage);
|
|
|
|
check_hittest(reporter, root, {
|
|
{{ -1, 0 }, nullptr },
|
|
{{ 0, -1 }, nullptr },
|
|
{{ 25, 0 }, nullptr },
|
|
{{ 0, 50 }, nullptr },
|
|
{{ 0, 0 }, d1 },
|
|
{{ 24, 49 }, d1 },
|
|
|
|
{{ 99, 50 }, nullptr },
|
|
{{ 100, 49 }, nullptr },
|
|
{{ 125, 50 }, nullptr },
|
|
{{ 100, 100 }, nullptr },
|
|
{{ 100, 50 }, d2 },
|
|
{{ 124, 99 }, d2 },
|
|
});
|
|
}
|
|
}
|
|
|
|
static void inval_test2(skiatest::Reporter* reporter) {
|
|
auto color = sksg::Color::Make(0xff000000);
|
|
auto rect = sksg::Rect::Make(SkRect::MakeWH(100, 100));
|
|
auto m1 = sksg::Matrix<SkMatrix>::Make(SkMatrix::I()),
|
|
m2 = sksg::Matrix<SkMatrix>::Make(SkMatrix::I());
|
|
auto t1 = sksg::TransformEffect::Make(sksg::Draw::Make(rect, color),
|
|
sksg::Transform::MakeConcat(m1, m2)),
|
|
t2 = sksg::TransformEffect::Make(sksg::Draw::Make(rect, color), m1);
|
|
auto root = sksg::Group::Make();
|
|
root->addChild(t1);
|
|
root->addChild(t2);
|
|
|
|
{
|
|
// Initial revalidation.
|
|
check_inval(reporter, root,
|
|
SkRect::MakeWH(100, 100),
|
|
SkRectPriv::MakeLargeS32(),
|
|
nullptr);
|
|
}
|
|
|
|
{
|
|
// Update the shared color.
|
|
color->setColor(0xffff0000);
|
|
std::vector<SkRect> damage = { {0, 0, 100, 100}, { 0, 0, 100, 100} };
|
|
check_inval(reporter, root,
|
|
SkRect::MakeWH(100, 100),
|
|
SkRect::MakeWH(100, 100),
|
|
&damage);
|
|
}
|
|
|
|
{
|
|
// Update m2.
|
|
m2->setMatrix(SkMatrix::MakeScale(2, 2));
|
|
std::vector<SkRect> damage = { {0, 0, 100, 100}, { 0, 0, 200, 200} };
|
|
check_inval(reporter, root,
|
|
SkRect::MakeWH(200, 200),
|
|
SkRect::MakeWH(200, 200),
|
|
&damage);
|
|
}
|
|
|
|
{
|
|
// Update shared m1.
|
|
m1->setMatrix(SkMatrix::MakeTrans(100, 100));
|
|
std::vector<SkRect> damage = { { 0, 0, 200, 200}, // draw1 prev bounds
|
|
{ 100, 100, 300, 300}, // draw1 new bounds
|
|
{ 0, 0, 100, 100}, // draw2 prev bounds
|
|
{ 100, 100, 200, 200} }; // draw2 new bounds
|
|
check_inval(reporter, root,
|
|
SkRect::MakeLTRB(100, 100, 300, 300),
|
|
SkRect::MakeLTRB( 0, 0, 300, 300),
|
|
&damage);
|
|
}
|
|
|
|
{
|
|
// Update shared rect.
|
|
rect->setR(50);
|
|
std::vector<SkRect> damage = { { 100, 100, 300, 300}, // draw1 prev bounds
|
|
{ 100, 100, 200, 300}, // draw1 new bounds
|
|
{ 100, 100, 200, 200}, // draw2 prev bounds
|
|
{ 100, 100, 150, 200} }; // draw2 new bounds
|
|
check_inval(reporter, root,
|
|
SkRect::MakeLTRB(100, 100, 200, 300),
|
|
SkRect::MakeLTRB(100, 100, 300, 300),
|
|
&damage);
|
|
}
|
|
}
|
|
|
|
static void inval_test3(skiatest::Reporter* reporter) {
|
|
auto color1 = sksg::Color::Make(0xff000000),
|
|
color2 = sksg::Color::Make(0xff000000);
|
|
auto group = sksg::Group::Make();
|
|
|
|
group->addChild(sksg::Draw::Make(sksg::Rect::Make(SkRect::MakeWH(100, 100)),
|
|
color1));
|
|
group->addChild(sksg::Draw::Make(sksg::Rect::Make(SkRect::MakeXYWH(200, 0, 100, 100)),
|
|
color2));
|
|
auto filter = sksg::DropShadowImageFilter::Make();
|
|
filter->setOffset({50, 75});
|
|
auto root = sksg::ImageFilterEffect::Make(group, filter);
|
|
|
|
{
|
|
// Initial revalidation.
|
|
check_inval(reporter, root,
|
|
SkRect::MakeXYWH(0, 0, 350, 175),
|
|
SkRectPriv::MakeLargeS32(),
|
|
nullptr);
|
|
}
|
|
|
|
{
|
|
// Shadow-only.
|
|
filter->setMode(sksg::DropShadowImageFilter::Mode::kShadowOnly);
|
|
std::vector<SkRect> damage = { {0, 0, 350, 175}, { 50, 75, 350, 175} };
|
|
check_inval(reporter, root,
|
|
SkRect::MakeLTRB(50, 75, 350, 175),
|
|
SkRect::MakeLTRB(0, 0, 350, 175),
|
|
&damage);
|
|
}
|
|
|
|
{
|
|
// Content change -> single/full filter bounds inval.
|
|
color1->setColor(0xffff0000);
|
|
std::vector<SkRect> damage = { { 50, 75, 350, 175} };
|
|
check_inval(reporter, root,
|
|
SkRect::MakeLTRB(50, 75, 350, 175),
|
|
SkRect::MakeLTRB(50, 75, 350, 175),
|
|
&damage);
|
|
}
|
|
|
|
}
|
|
|
|
static void inval_group_remove(skiatest::Reporter* reporter) {
|
|
auto draw = sksg::Draw::Make(sksg::Rect::Make(SkRect::MakeWH(100, 100)),
|
|
sksg::Color::Make(SK_ColorBLACK));
|
|
auto grp = sksg::Group::Make();
|
|
|
|
// Readding the child should not trigger asserts.
|
|
grp->addChild(draw);
|
|
grp->removeChild(draw);
|
|
grp->addChild(draw);
|
|
}
|
|
|
|
DEF_TEST(SGInvalidation, reporter) {
|
|
inval_test1(reporter);
|
|
inval_test2(reporter);
|
|
inval_test3(reporter);
|
|
inval_group_remove(reporter);
|
|
}
|
|
|
|
#endif // !defined(SK_BUILD_FOR_GOOGLE3)
|