Home | History | Annotate | Download | only in gm
      1 /*
      2  * Copyright 2015 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 "gm.h"
      9 #include "SkCanvas.h"
     10 #include "SkPath.h"
     11 
     12 namespace {
     13 // Concave test
     14 void test_concave(SkCanvas* canvas, const SkPaint& paint) {
     15     SkPath path;
     16     canvas->translate(0, 0);
     17     path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
     18     path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
     19     path.lineTo(SkIntToScalar(30), SkIntToScalar(30));
     20     path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
     21     canvas->drawPath(path, paint);
     22 }
     23 
     24 // Reverse concave test
     25 void test_reverse_concave(SkCanvas* canvas, const SkPaint& paint) {
     26     SkPath path;
     27     canvas->save();
     28     canvas->translate(100, 0);
     29     path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
     30     path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
     31     path.lineTo(SkIntToScalar(30), SkIntToScalar(30));
     32     path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
     33     canvas->drawPath(path, paint);
     34     canvas->restore();
     35 }
     36 
     37 // Bowtie (intersection)
     38 void test_bowtie(SkCanvas* canvas, const SkPaint& paint) {
     39     SkPath path;
     40     canvas->save();
     41     canvas->translate(200, 0);
     42     path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
     43     path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
     44     path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
     45     path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
     46     canvas->drawPath(path, paint);
     47     canvas->restore();
     48 }
     49 
     50 // "fake" bowtie (concave, but no intersection)
     51 void test_fake_bowtie(SkCanvas* canvas, const SkPaint& paint) {
     52     SkPath path;
     53     canvas->save();
     54     canvas->translate(300, 0);
     55     path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
     56     path.lineTo(SkIntToScalar(50), SkIntToScalar(40));
     57     path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
     58     path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
     59     path.lineTo(SkIntToScalar(50), SkIntToScalar(60));
     60     path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
     61     canvas->drawPath(path, paint);
     62     canvas->restore();
     63 }
     64 
     65 // Bowtie with a smaller right hand lobe. The outer vertex of the left hand
     66 // lobe intrudes into the interior of the right hand lobe.
     67 void test_intruding_vertex(SkCanvas* canvas, const SkPaint& paint) {
     68     SkPath path;
     69     canvas->save();
     70     canvas->translate(400, 0);
     71     path.setIsVolatile(true);
     72     path.moveTo(20, 20);
     73     path.lineTo(50, 50);
     74     path.lineTo(68, 20);
     75     path.lineTo(68, 80);
     76     path.lineTo(50, 50);
     77     path.lineTo(20, 80);
     78     canvas->drawPath(path, paint);
     79     canvas->restore();
     80 }
     81 
     82 // A shape with an edge that becomes inverted on AA stroking and that also contains
     83 // a repeated start/end vertex.
     84 void test_inversion_repeat_vertex(SkCanvas* canvas, const SkPaint& paint) {
     85     SkPath path;
     86     canvas->save();
     87     canvas->translate(400, 100);
     88     path.setIsVolatile(true);
     89     path.moveTo(80,     50);
     90     path.lineTo(40,     80);
     91     path.lineTo(60,     20);
     92     path.lineTo(20,     20);
     93     path.lineTo(39.99f, 80);
     94     path.lineTo(80,     50);
     95     canvas->drawPath(path, paint);
     96     canvas->restore();
     97 }
     98 
     99 // Fish test (intersection/concave)
    100 void test_fish(SkCanvas* canvas, const SkPaint& paint) {
    101     SkPath path;
    102     canvas->save();
    103     canvas->translate(0, 100);
    104     path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
    105     path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
    106     path.lineTo(SkIntToScalar(70), SkIntToScalar(50));
    107     path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
    108     path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
    109     path.lineTo(SkIntToScalar(0), SkIntToScalar(50));
    110     canvas->drawPath(path, paint);
    111     canvas->restore();
    112 }
    113 
    114 // Overlapping "Fast-forward" icon: tests coincidence of inner and outer
    115 // vertices generated by intersection.
    116 void test_fast_forward(SkCanvas* canvas, const SkPaint& paint) {
    117     SkPath path;
    118     canvas->save();
    119     canvas->translate(100, 100);
    120     path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
    121     path.lineTo(SkIntToScalar(60), SkIntToScalar(50));
    122     path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
    123     path.moveTo(SkIntToScalar(40), SkIntToScalar(20));
    124     path.lineTo(SkIntToScalar(40), SkIntToScalar(80));
    125     path.lineTo(SkIntToScalar(80), SkIntToScalar(50));
    126     canvas->drawPath(path, paint);
    127     canvas->restore();
    128 }
    129 
    130 // Square polygon with a square hole.
    131 void test_hole(SkCanvas* canvas, const SkPaint& paint) {
    132     SkPath path;
    133     canvas->save();
    134     canvas->translate(200, 100);
    135     path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
    136     path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
    137     path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
    138     path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
    139     path.moveTo(SkIntToScalar(30), SkIntToScalar(30));
    140     path.lineTo(SkIntToScalar(30), SkIntToScalar(70));
    141     path.lineTo(SkIntToScalar(70), SkIntToScalar(70));
    142     path.lineTo(SkIntToScalar(70), SkIntToScalar(30));
    143     canvas->drawPath(path, paint);
    144     canvas->restore();
    145 }
    146 
    147 // Star test (self-intersecting)
    148 void test_star(SkCanvas* canvas, const SkPaint& paint) {
    149     SkPath path;
    150     canvas->save();
    151     canvas->translate(300, 100);
    152     path.moveTo(30, 20);
    153     path.lineTo(50, 80);
    154     path.lineTo(70, 20);
    155     path.lineTo(20, 57);
    156     path.lineTo(80, 57);
    157     path.close();
    158     canvas->drawPath(path, paint);
    159     canvas->restore();
    160 }
    161 
    162 // Exercise a case where the intersection is below a bottom edge.
    163 void test_twist(SkCanvas* canvas, const SkPaint& paint) {
    164     SkPath path;
    165     canvas->save();
    166     path.moveTo(                 0.5,                    6);
    167     path.lineTo(5.8070392608642578125, 6.4612660408020019531);
    168     path.lineTo(-2.9186885356903076172, 2.811046600341796875);
    169     path.lineTo(0.49999994039535522461, -1.4124038219451904297);
    170     canvas->translate(420, 220);
    171     canvas->scale(10, 10);
    172     canvas->drawPath(path, paint);
    173     canvas->restore();
    174 }
    175 
    176 // Stairstep with repeated vert (intersection)
    177 void test_stairstep(SkCanvas* canvas, const SkPaint& paint) {
    178     SkPath path;
    179     canvas->save();
    180     canvas->translate(0, 200);
    181     path.moveTo(SkIntToScalar(50), SkIntToScalar(50));
    182     path.lineTo(SkIntToScalar(50), SkIntToScalar(20));
    183     path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
    184     path.lineTo(SkIntToScalar(50), SkIntToScalar(50));
    185     path.lineTo(SkIntToScalar(20), SkIntToScalar(50));
    186     path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
    187     canvas->drawPath(path, paint);
    188     canvas->restore();
    189 }
    190 
    191 void test_stairstep2(SkCanvas* canvas, const SkPaint& paint) {
    192     SkPath path;
    193     canvas->save();
    194     canvas->translate(100, 200);
    195     path.moveTo(20, 60);
    196     path.lineTo(35, 80);
    197     path.lineTo(50, 60);
    198     path.lineTo(65, 80);
    199     path.lineTo(80, 60);
    200     canvas->drawPath(path, paint);
    201     canvas->restore();
    202 }
    203 
    204 // Overlapping segments
    205 void test_overlapping(SkCanvas* canvas, const SkPaint& paint) {
    206     SkPath path;
    207     canvas->save();
    208     canvas->translate(200, 200);
    209     path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
    210     path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
    211     path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
    212     path.lineTo(SkIntToScalar(80), SkIntToScalar(30));
    213     canvas->drawPath(path, paint);
    214     canvas->restore();
    215 }
    216 
    217 // Two "island" triangles inside a containing rect.
    218 // This exercises the partnering code in the tessellator.
    219 void test_partners(SkCanvas* canvas, const SkPaint& paint) {
    220     SkPath path;
    221     canvas->save();
    222     canvas->translate(300, 200);
    223     path.moveTo(20, 80);
    224     path.lineTo(80, 80);
    225     path.lineTo(80, 20);
    226     path.lineTo(20, 20);
    227     path.moveTo(30, 30);
    228     path.lineTo(45, 50);
    229     path.lineTo(30, 70);
    230     path.moveTo(70, 30);
    231     path.lineTo(70, 70);
    232     path.lineTo(55, 50);
    233     canvas->drawPath(path, paint);
    234     canvas->restore();
    235 }
    236 
    237 // Monotone test 1 (point in the middle)
    238 void test_monotone_1(SkCanvas* canvas, const SkPaint& paint) {
    239     SkPath path;
    240     canvas->save();
    241     canvas->translate(0, 300);
    242     path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
    243     path.quadTo(SkIntToScalar(20), SkIntToScalar(50),
    244                 SkIntToScalar(80), SkIntToScalar(50));
    245     path.quadTo(SkIntToScalar(20), SkIntToScalar(50),
    246                 SkIntToScalar(20), SkIntToScalar(80));
    247     canvas->drawPath(path, paint);
    248     canvas->restore();
    249 }
    250 
    251 // Monotone test 2 (point at the top)
    252 void test_monotone_2(SkCanvas* canvas, const SkPaint& paint) {
    253     SkPath path;
    254     canvas->save();
    255     canvas->translate(100, 300);
    256     path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
    257     path.lineTo(SkIntToScalar(80), SkIntToScalar(30));
    258     path.quadTo(SkIntToScalar(20), SkIntToScalar(20),
    259                 SkIntToScalar(20), SkIntToScalar(80));
    260     canvas->drawPath(path, paint);
    261     canvas->restore();
    262 }
    263 
    264 // Monotone test 3 (point at the bottom)
    265 void test_monotone_3(SkCanvas* canvas, const SkPaint& paint) {
    266     SkPath path;
    267     canvas->save();
    268     canvas->translate(200, 300);
    269     path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
    270     path.lineTo(SkIntToScalar(80), SkIntToScalar(70));
    271     path.quadTo(SkIntToScalar(20), SkIntToScalar(80),
    272                 SkIntToScalar(20), SkIntToScalar(20));
    273     canvas->drawPath(path, paint);
    274     canvas->restore();
    275 }
    276 
    277 // Monotone test 4 (merging of two monotones)
    278 void test_monotone_4(SkCanvas* canvas, const SkPaint& paint) {
    279     SkPath path;
    280     canvas->save();
    281     canvas->translate(300, 300);
    282     path.moveTo(80, 25);
    283     path.lineTo(50, 39);
    284     path.lineTo(20, 25);
    285     path.lineTo(40, 45);
    286     path.lineTo(70, 50);
    287     path.lineTo(80, 80);
    288     canvas->drawPath(path, paint);
    289     canvas->restore();
    290 }
    291 
    292 // Monotone test 5 (aborted merging of two monotones)
    293 void test_monotone_5(SkCanvas* canvas, const SkPaint& paint) {
    294     SkPath path;
    295     canvas->save();
    296     canvas->translate(0, 400);
    297     path.moveTo(50, 20);
    298     path.lineTo(80, 80);
    299     path.lineTo(50, 50);
    300     path.lineTo(20, 80);
    301     canvas->drawPath(path, paint);
    302     canvas->restore();
    303 }
    304 // Degenerate intersection test
    305 void test_degenerate(SkCanvas* canvas, const SkPaint& paint) {
    306     SkPath path;
    307     canvas->save();
    308     canvas->translate(100, 400);
    309     path.moveTo(50, 20);
    310     path.lineTo(70, 30);
    311     path.lineTo(20, 50);
    312     path.moveTo(50, 20);
    313     path.lineTo(80, 80);
    314     path.lineTo(50, 80);
    315     canvas->drawPath(path, paint);
    316     canvas->restore();
    317 }
    318 // Two triangles with a coincident edge.
    319 void test_coincident_edge(SkCanvas* canvas, const SkPaint& paint) {
    320     SkPath path;
    321     canvas->save();
    322     canvas->translate(200, 400);
    323 
    324     path.moveTo(80, 20);
    325     path.lineTo(80, 80);
    326     path.lineTo(20, 80);
    327 
    328     path.moveTo(20, 20);
    329     path.lineTo(80, 80);
    330     path.lineTo(20, 80);
    331 
    332     canvas->drawPath(path, paint);
    333     canvas->restore();
    334 }
    335 // Bowtie with a coincident triangle (one triangle vertex coincident with the
    336 // bowtie's intersection).
    337 void test_bowtie_coincident_triangle(SkCanvas* canvas, const SkPaint& paint) {
    338     SkPath path;
    339     canvas->save();
    340     canvas->translate(300, 400);
    341     path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
    342     path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
    343     path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
    344     path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
    345     path.moveTo(SkIntToScalar(50), SkIntToScalar(50));
    346     path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
    347     path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
    348     canvas->drawPath(path, paint);
    349     canvas->restore();
    350 }
    351 
    352 // Coincident edges (big ones first, coincident vert on top).
    353 void test_coincident_edges_1(SkCanvas* canvas, const SkPaint& paint) {
    354     SkPath path;
    355     canvas->save();
    356     canvas->translate(0, 500);
    357     path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
    358     path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
    359     path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
    360     path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
    361     path.lineTo(SkIntToScalar(50), SkIntToScalar(50));
    362     path.lineTo(SkIntToScalar(20), SkIntToScalar(50));
    363     canvas->drawPath(path, paint);
    364     canvas->restore();
    365 }
    366 // Coincident edges (small ones first, coincident vert on top).
    367 void test_coincident_edges_2(SkCanvas* canvas, const SkPaint& paint) {
    368     SkPath path;
    369     canvas->save();
    370     canvas->translate(100, 500);
    371     path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
    372     path.lineTo(SkIntToScalar(50), SkIntToScalar(50));
    373     path.lineTo(SkIntToScalar(20), SkIntToScalar(50));
    374     path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
    375     path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
    376     path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
    377     canvas->drawPath(path, paint);
    378     canvas->restore();
    379 }
    380 // Coincident edges (small ones first, coincident vert on bottom).
    381 void test_coincident_edges_3(SkCanvas* canvas, const SkPaint& paint) {
    382     SkPath path;
    383     canvas->save();
    384     canvas->translate(200, 500);
    385     path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
    386     path.lineTo(SkIntToScalar(20), SkIntToScalar(50));
    387     path.lineTo(SkIntToScalar(50), SkIntToScalar(50));
    388     path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
    389     path.lineTo(SkIntToScalar(20), SkIntToScalar(20));
    390     path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
    391     canvas->drawPath(path, paint);
    392     canvas->restore();
    393 }
    394 // Coincident edges (big ones first, coincident vert on bottom).
    395 void test_coincident_edges_4(SkCanvas* canvas, const SkPaint& paint) {
    396     SkPath path;
    397     canvas->save();
    398     canvas->translate(300, 500);
    399     path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
    400     path.lineTo(SkIntToScalar(20), SkIntToScalar(20));
    401     path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
    402     path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
    403     path.lineTo(SkIntToScalar(20), SkIntToScalar(50));
    404     path.lineTo(SkIntToScalar(50), SkIntToScalar(50));
    405     canvas->drawPath(path, paint);
    406     canvas->restore();
    407 }
    408 
    409 };
    410 
    411 DEF_SIMPLE_GM(concavepaths, canvas, 500, 600) {
    412     SkPaint paint;
    413 
    414     paint.setAntiAlias(true);
    415     paint.setStyle(SkPaint::kFill_Style);
    416 
    417     test_concave(canvas, paint);
    418     test_reverse_concave(canvas, paint);
    419     test_bowtie(canvas, paint);
    420     test_fake_bowtie(canvas, paint);
    421     test_intruding_vertex(canvas, paint);
    422     test_fish(canvas, paint);
    423     test_fast_forward(canvas, paint);
    424     test_hole(canvas, paint);
    425     test_star(canvas, paint);
    426     test_twist(canvas, paint);
    427     test_inversion_repeat_vertex(canvas, paint);
    428     test_stairstep(canvas, paint);
    429     test_stairstep2(canvas, paint);
    430     test_overlapping(canvas, paint);
    431     test_partners(canvas, paint);
    432     test_monotone_1(canvas, paint);
    433     test_monotone_2(canvas, paint);
    434     test_monotone_3(canvas, paint);
    435     test_monotone_4(canvas, paint);
    436     test_monotone_5(canvas, paint);
    437     test_degenerate(canvas, paint);
    438     test_coincident_edge(canvas, paint);
    439     test_bowtie_coincident_triangle(canvas, paint);
    440     test_coincident_edges_1(canvas, paint);
    441     test_coincident_edges_2(canvas, paint);
    442     test_coincident_edges_3(canvas, paint);
    443     test_coincident_edges_4(canvas, paint);
    444 }
    445