Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright 2011 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkTypes.h"
      9 
     10 #if !defined(SK_BUILD_FOR_GOOGLE3)
     11 
     12 #include "SkRect.h"
     13 #include "SkRectPriv.h"
     14 #include "SkSGColor.h"
     15 #include "SkSGDraw.h"
     16 #include "SkSGGroup.h"
     17 #include "SkSGInvalidationController.h"
     18 #include "SkSGRect.h"
     19 #include "SkSGRenderEffect.h"
     20 #include "SkSGTransform.h"
     21 #include "SkTo.h"
     22 
     23 #include "Test.h"
     24 
     25 #include <vector>
     26 
     27 static void check_inval(skiatest::Reporter* reporter, const sk_sp<sksg::Node>& root,
     28                         const SkRect& expected_bounds,
     29                         const SkRect& expected_inval_bounds,
     30                         const std::vector<SkRect>* expected_damage) {
     31     sksg::InvalidationController ic;
     32     const auto bbox = root->revalidate(&ic, SkMatrix::I());
     33 
     34     if (0) {
     35         SkDebugf("** bbox: [%f %f %f %f], ibbox: [%f %f %f %f]\n",
     36                  bbox.fLeft, bbox.fTop, bbox.fRight, bbox.fBottom,
     37                  ic.bounds().left(), ic.bounds().top(), ic.bounds().right(), ic.bounds().bottom());
     38     }
     39 
     40     REPORTER_ASSERT(reporter, bbox == expected_bounds);
     41     REPORTER_ASSERT(reporter, ic.bounds() == expected_inval_bounds);
     42 
     43     if (expected_damage) {
     44         const auto damage_count = SkTo<size_t>(ic.end() - ic.begin());
     45         REPORTER_ASSERT(reporter, expected_damage->size() == damage_count);
     46         for (size_t i = 0; i < std::min(expected_damage->size(), damage_count); ++i) {
     47             const auto r1 = (*expected_damage)[i],
     48                        r2 = ic.begin()[i];
     49             if (0) {
     50                 SkDebugf("*** expected inval: [%f %f %f %f], actual: [%f %f %f %f]\n",
     51                          r1.left(), r1.top(), r1.right(), r1.bottom(),
     52                          r2.left(), r2.top(), r2.right(), r2.bottom());
     53             }
     54             REPORTER_ASSERT(reporter, r1 == r2);
     55         }
     56     }
     57 }
     58 
     59 struct HitTest {
     60     const SkPoint           pt;
     61     sk_sp<sksg::RenderNode> node;
     62 };
     63 
     64 static void check_hittest(skiatest::Reporter* reporter, const sk_sp<sksg::RenderNode>& root,
     65                           const std::vector<HitTest>& tests) {
     66     for (const auto& tst : tests) {
     67         const auto* node = root->nodeAt(tst.pt);
     68         if (node != tst.node.get()) {
     69             SkDebugf("*** nodeAt(%f, %f) - expected %p, got %p\n",
     70                      tst.pt.x(), tst.pt.y(), tst.node.get(), node);
     71         }
     72         REPORTER_ASSERT(reporter, tst.node.get() == node);
     73     }
     74 }
     75 
     76 static void inval_test1(skiatest::Reporter* reporter) {
     77     auto color  = sksg::Color::Make(0xff000000);
     78     auto r1     = sksg::Rect::Make(SkRect::MakeWH(100, 100)),
     79          r2     = sksg::Rect::Make(SkRect::MakeWH(100, 100));
     80     auto grp    = sksg::Group::Make();
     81     auto matrix = sksg::Matrix<SkMatrix>::Make(SkMatrix::I());
     82     auto root   = sksg::TransformEffect::Make(grp, matrix);
     83     auto d1     = sksg::Draw::Make(r1, color),
     84          d2     = sksg::Draw::Make(r2, color);
     85 
     86     grp->addChild(d1);
     87     grp->addChild(d2);
     88 
     89     {
     90         // Initial revalidation.
     91         check_inval(reporter, root,
     92                     SkRect::MakeWH(100, 100),
     93                     SkRectPriv::MakeLargeS32(),
     94                     nullptr);
     95 
     96         check_hittest(reporter, root, {
     97                           {{  -1,   0 }, nullptr },
     98                           {{   0,  -1 }, nullptr },
     99                           {{ 100,   0 }, nullptr },
    100                           {{   0, 100 }, nullptr },
    101                           {{   0,   0 },      d2 },
    102                           {{  99,  99 },      d2 },
    103                       });
    104     }
    105 
    106     {
    107         // Move r2 to (200 100).
    108         r2->setL(200); r2->setT(100); r2->setR(300); r2->setB(200);
    109         std::vector<SkRect> damage = { {0, 0, 100, 100}, { 200, 100, 300, 200} };
    110         check_inval(reporter, root,
    111                     SkRect::MakeWH(300, 200),
    112                     SkRect::MakeWH(300, 200),
    113                     &damage);
    114 
    115         check_hittest(reporter, root, {
    116                           {{  -1,   0 }, nullptr },
    117                           {{   0,  -1 }, nullptr },
    118                           {{ 100,   0 }, nullptr },
    119                           {{   0, 100 }, nullptr },
    120                           {{   0,   0 },      d1 },
    121                           {{  99,  99 },      d1 },
    122 
    123                           {{ 199, 100 }, nullptr },
    124                           {{ 200,  99 }, nullptr },
    125                           {{ 300, 100 }, nullptr },
    126                           {{ 200, 200 }, nullptr },
    127                           {{ 200, 100 },      d2 },
    128                           {{ 299, 199 },      d2 },
    129                       });
    130     }
    131 
    132     {
    133         // Update the common color.
    134         color->setColor(0xffff0000);
    135         std::vector<SkRect> damage = { {0, 0, 100, 100}, { 200, 100, 300, 200} };
    136         check_inval(reporter, root,
    137                     SkRect::MakeWH(300, 200),
    138                     SkRect::MakeWH(300, 200),
    139                     &damage);
    140     }
    141 
    142     {
    143         // Shrink r1.
    144         r1->setR(50);
    145         std::vector<SkRect> damage = { {0, 0, 100, 100}, { 0, 0, 50, 100} };
    146         check_inval(reporter, root,
    147                     SkRect::MakeWH(300, 200),
    148                     SkRect::MakeWH(100, 100),
    149                     &damage);
    150 
    151         check_hittest(reporter, root, {
    152                           {{  -1,   0 }, nullptr },
    153                           {{   0,  -1 }, nullptr },
    154                           {{  50,   0 }, nullptr },
    155                           {{   0, 100 }, nullptr },
    156                           {{   0,   0 },      d1 },
    157                           {{  49,  99 },      d1 },
    158 
    159                           {{ 199, 100 }, nullptr },
    160                           {{ 200,  99 }, nullptr },
    161                           {{ 300, 100 }, nullptr },
    162                           {{ 200, 200 }, nullptr },
    163                           {{ 200, 100 },      d2 },
    164                           {{ 299, 199 },      d2 },
    165                       });
    166     }
    167 
    168     {
    169         // Update transform.
    170         matrix->setMatrix(SkMatrix::MakeScale(2, 2));
    171         std::vector<SkRect> damage = { {0, 0, 300, 200}, { 0, 0, 600, 400} };
    172         check_inval(reporter, root,
    173                     SkRect::MakeWH(600, 400),
    174                     SkRect::MakeWH(600, 400),
    175                     &damage);
    176 
    177         check_hittest(reporter, root, {
    178                           {{  -1,   0 }, nullptr },
    179                           {{   0,  -1 }, nullptr },
    180                           {{  25,   0 }, nullptr },
    181                           {{   0,  50 }, nullptr },
    182                           {{   0,   0 },      d1 },
    183                           {{  24,  49 },      d1 },
    184 
    185                           {{  99,  50 }, nullptr },
    186                           {{ 100,  49 }, nullptr },
    187                           {{ 150,  50 }, nullptr },
    188                           {{ 100, 100 }, nullptr },
    189                           {{ 100,  50 },      d2 },
    190                           {{ 149,  99 },      d2 },
    191                       });
    192     }
    193 
    194     {
    195         // Shrink r2 under transform.
    196         r2->setR(250);
    197         std::vector<SkRect> damage = { {400, 200, 600, 400}, { 400, 200, 500, 400} };
    198         check_inval(reporter, root,
    199                     SkRect::MakeWH(500, 400),
    200                     SkRect::MakeLTRB(400, 200, 600, 400),
    201                     &damage);
    202 
    203         check_hittest(reporter, root, {
    204                           {{  -1,   0 }, nullptr },
    205                           {{   0,  -1 }, nullptr },
    206                           {{  25,   0 }, nullptr },
    207                           {{   0,  50 }, nullptr },
    208                           {{   0,   0 },      d1 },
    209                           {{  24,  49 },      d1 },
    210 
    211                           {{  99,  50 }, nullptr },
    212                           {{ 100,  49 }, nullptr },
    213                           {{ 125,  50 }, nullptr },
    214                           {{ 100, 100 }, nullptr },
    215                           {{ 100,  50 },      d2 },
    216                           {{ 124,  99 },      d2 },
    217                       });
    218     }
    219 }
    220 
    221 static void inval_test2(skiatest::Reporter* reporter) {
    222     auto color = sksg::Color::Make(0xff000000);
    223     auto rect  = sksg::Rect::Make(SkRect::MakeWH(100, 100));
    224     auto m1    = sksg::Matrix<SkMatrix>::Make(SkMatrix::I()),
    225          m2    = sksg::Matrix<SkMatrix>::Make(SkMatrix::I());
    226     auto t1    = sksg::TransformEffect::Make(sksg::Draw::Make(rect, color),
    227                                              sksg::Transform::MakeConcat(m1, m2)),
    228          t2    = sksg::TransformEffect::Make(sksg::Draw::Make(rect, color), m1);
    229     auto root  = sksg::Group::Make();
    230     root->addChild(t1);
    231     root->addChild(t2);
    232 
    233     {
    234         // Initial revalidation.
    235         check_inval(reporter, root,
    236                     SkRect::MakeWH(100, 100),
    237                     SkRectPriv::MakeLargeS32(),
    238                     nullptr);
    239     }
    240 
    241     {
    242         // Update the shared color.
    243         color->setColor(0xffff0000);
    244         std::vector<SkRect> damage = { {0, 0, 100, 100}, { 0, 0, 100, 100} };
    245         check_inval(reporter, root,
    246                     SkRect::MakeWH(100, 100),
    247                     SkRect::MakeWH(100, 100),
    248                     &damage);
    249     }
    250 
    251     {
    252         // Update m2.
    253         m2->setMatrix(SkMatrix::MakeScale(2, 2));
    254         std::vector<SkRect> damage = { {0, 0, 100, 100}, { 0, 0, 200, 200} };
    255         check_inval(reporter, root,
    256                     SkRect::MakeWH(200, 200),
    257                     SkRect::MakeWH(200, 200),
    258                     &damage);
    259     }
    260 
    261     {
    262         // Update shared m1.
    263         m1->setMatrix(SkMatrix::MakeTrans(100, 100));
    264         std::vector<SkRect> damage = { {   0,   0, 200, 200},   // draw1 prev bounds
    265                                        { 100, 100, 300, 300},   // draw1 new bounds
    266                                        {   0,   0, 100, 100},   // draw2 prev bounds
    267                                        { 100, 100, 200, 200} }; // draw2 new bounds
    268         check_inval(reporter, root,
    269                     SkRect::MakeLTRB(100, 100, 300, 300),
    270                     SkRect::MakeLTRB(  0,   0, 300, 300),
    271                     &damage);
    272     }
    273 
    274     {
    275         // Update shared rect.
    276         rect->setR(50);
    277         std::vector<SkRect> damage = { { 100, 100, 300, 300},   // draw1 prev bounds
    278                                        { 100, 100, 200, 300},   // draw1 new bounds
    279                                        { 100, 100, 200, 200},   // draw2 prev bounds
    280                                        { 100, 100, 150, 200} }; // draw2 new bounds
    281         check_inval(reporter, root,
    282                     SkRect::MakeLTRB(100, 100, 200, 300),
    283                     SkRect::MakeLTRB(100, 100, 300, 300),
    284                     &damage);
    285     }
    286 }
    287 
    288 static void inval_test3(skiatest::Reporter* reporter) {
    289     auto color1 = sksg::Color::Make(0xff000000),
    290          color2 = sksg::Color::Make(0xff000000);
    291     auto group  = sksg::Group::Make();
    292 
    293     group->addChild(sksg::Draw::Make(sksg::Rect::Make(SkRect::MakeWH(100, 100)),
    294                                      color1));
    295     group->addChild(sksg::Draw::Make(sksg::Rect::Make(SkRect::MakeXYWH(200, 0, 100, 100)),
    296                                      color2));
    297     auto filter = sksg::DropShadowImageFilter::Make();
    298     filter->setOffset({50, 75});
    299     auto root = sksg::ImageFilterEffect::Make(group, filter);
    300 
    301     {
    302         // Initial revalidation.
    303         check_inval(reporter, root,
    304                     SkRect::MakeXYWH(0, 0, 350, 175),
    305                     SkRectPriv::MakeLargeS32(),
    306                     nullptr);
    307     }
    308 
    309     {
    310         // Shadow-only.
    311         filter->setMode(sksg::DropShadowImageFilter::Mode::kShadowOnly);
    312         std::vector<SkRect> damage = { {0, 0, 350, 175}, { 50, 75, 350, 175} };
    313         check_inval(reporter, root,
    314                     SkRect::MakeLTRB(50, 75, 350, 175),
    315                     SkRect::MakeLTRB(0, 0, 350, 175),
    316                     &damage);
    317     }
    318 
    319     {
    320         // Content change -> single/full filter bounds inval.
    321         color1->setColor(0xffff0000);
    322         std::vector<SkRect> damage = { { 50, 75, 350, 175} };
    323         check_inval(reporter, root,
    324                     SkRect::MakeLTRB(50, 75, 350, 175),
    325                     SkRect::MakeLTRB(50, 75, 350, 175),
    326                     &damage);
    327     }
    328 
    329 }
    330 
    331 static void inval_group_remove(skiatest::Reporter* reporter) {
    332     auto draw = sksg::Draw::Make(sksg::Rect::Make(SkRect::MakeWH(100, 100)),
    333                                  sksg::Color::Make(SK_ColorBLACK));
    334     auto grp = sksg::Group::Make();
    335 
    336     // Readding the child should not trigger asserts.
    337     grp->addChild(draw);
    338     grp->removeChild(draw);
    339     grp->addChild(draw);
    340 }
    341 
    342 DEF_TEST(SGInvalidation, reporter) {
    343     inval_test1(reporter);
    344     inval_test2(reporter);
    345     inval_test3(reporter);
    346     inval_group_remove(reporter);
    347 }
    348 
    349 #endif // !defined(SK_BUILD_FOR_GOOGLE3)
    350