Home | History | Annotate | Download | only in gm
      1 /*
      2  * Copyright 2016 Google Inc.
      3  *
      4  * Use of this source code is governed by a BD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "gm.h"
      9 #include "SkParsePath.h"
     10 #include "SkPath.h"
     11 
     12 /*
     13 The arcto test below should draw the same as this SVG:
     14 (Note that Skia's arcTo Direction parameter value is opposite SVG's sweep value, e.g. 0 / 1)
     15 
     16 <svg width="500" height="600">
     17 <path d="M 50,100 A50,50,   0,0,1, 150,200" style="stroke:#660000; fill:none; stroke-width:2" />
     18 <path d="M100,100 A50,100,  0,0,1, 200,200" style="stroke:#660000; fill:none; stroke-width:2" />
     19 <path d="M150,100 A50,50,  45,0,1, 250,200" style="stroke:#660000; fill:none; stroke-width:2" />
     20 <path d="M200,100 A50,100, 45,0,1, 300,200" style="stroke:#660000; fill:none; stroke-width:2" />
     21 
     22 <path d="M150,200 A50,50,   0,1,0, 150,300" style="stroke:#660000; fill:none; stroke-width:2" />
     23 <path d="M200,200 A50,100,  0,1,0, 200,300" style="stroke:#660000; fill:none; stroke-width:2" />
     24 <path d="M250,200 A50,50,  45,1,0, 250,300" style="stroke:#660000; fill:none; stroke-width:2" />
     25 <path d="M300,200 A50,100, 45,1,0, 300,300" style="stroke:#660000; fill:none; stroke-width:2" />
     26 
     27 <path d="M250,400  A120,80 0 0,0 250,500"
     28     fill="none" stroke="red" stroke-width="5" />
     29 
     30 <path d="M250,400  A120,80 0 1,1 250,500"
     31     fill="none" stroke="green" stroke-width="5"/>
     32 
     33 <path d="M250,400  A120,80 0 1,0 250,500"
     34     fill="none" stroke="purple" stroke-width="5"/>
     35 
     36 <path d="M250,400  A120,80 0 0,1 250,500"
     37     fill="none" stroke="blue" stroke-width="5"/>
     38 
     39 <path d="M100,100  A  0, 0 0 0,1 200,200"
     40     fill="none" stroke="blue" stroke-width="5" stroke-linecap="round"/>
     41 
     42 <path d="M200,100  A 80,80 0 0,1 200,100"
     43     fill="none" stroke="blue" stroke-width="5" stroke-linecap="round"/>
     44 </svg>
     45  */
     46 
     47 DEF_SIMPLE_GM(arcto, canvas, 500, 600) {
     48     SkPaint paint;
     49     paint.setAntiAlias(true);
     50     paint.setStyle(SkPaint::kStroke_Style);
     51     paint.setStrokeWidth(2);
     52     paint.setColor(0xFF660000);
     53 //    canvas->scale(2, 2);  // for testing on retina
     54     SkRect oval = SkRect::MakeXYWH(100, 100, 100, 100);
     55     SkPath svgArc;
     56 
     57     for (int angle = 0; angle <= 45; angle += 45) {
     58        for (int oHeight = 2; oHeight >= 1; --oHeight) {
     59             SkScalar ovalHeight = oval.height() / oHeight;
     60             svgArc.moveTo(oval.fLeft, oval.fTop);
     61             svgArc.arcTo(oval.width() / 2, ovalHeight, SkIntToScalar(angle), SkPath::kSmall_ArcSize,
     62                     SkPath::kCW_Direction, oval.right(), oval.bottom());
     63             canvas->drawPath(svgArc, paint);
     64             svgArc.reset();
     65 
     66             svgArc.moveTo(oval.fLeft + 100, oval.fTop + 100);
     67             svgArc.arcTo(oval.width() / 2, ovalHeight, SkIntToScalar(angle), SkPath::kLarge_ArcSize,
     68                     SkPath::kCCW_Direction, oval.right(), oval.bottom() + 100);
     69             canvas->drawPath(svgArc, paint);
     70             oval.offset(50, 0);
     71             svgArc.reset();
     72 
     73         }
     74     }
     75 
     76     paint.setStrokeWidth(5);
     77     const SkColor purple = 0xFF800080;
     78     const SkColor darkgreen = 0xFF008000;
     79     const SkColor colors[] = { SK_ColorRED, darkgreen, purple, SK_ColorBLUE };
     80     const char* arcstrs[] = {
     81         "M250,400  A120,80 0 0,0 250,500",
     82         "M250,400  A120,80 0 1,1 250,500",
     83         "M250,400  A120,80 0 1,0 250,500",
     84         "M250,400  A120,80 0 0,1 250,500"
     85     };
     86     int cIndex = 0;
     87     for (const char* arcstr : arcstrs) {
     88         SkParsePath::FromSVGString(arcstr, &svgArc);
     89         paint.setColor(colors[cIndex++]);
     90         canvas->drawPath(svgArc, paint);
     91     }
     92 
     93     // test that zero length arcs still draw round cap
     94     paint.setStrokeCap(SkPaint::kRound_Cap);
     95     SkPath path;
     96     path.moveTo(100, 100);
     97     path.arcTo(0, 0, 0, SkPath::kLarge_ArcSize, SkPath::kCW_Direction, 200, 200);
     98     canvas->drawPath(path, paint);
     99 
    100     path.reset();
    101     path.moveTo(200, 100);
    102     path.arcTo(80, 80, 0, SkPath::kLarge_ArcSize, SkPath::kCW_Direction, 200, 100);
    103     canvas->drawPath(path, paint);
    104 }
    105 
    106 #include "random_parse_path.h"
    107 #include "SkRandom.h"
    108 
    109 /* The test below generates a reference image using SVG. To compare the result for correctness,
    110    enable the define below and then view the generated SVG in a browser.
    111  */
    112 #define GENERATE_SVG_REFERENCE 0
    113 
    114 #if GENERATE_SVG_REFERENCE
    115 #include "SkOSFile.h"
    116 #endif
    117 
    118 enum {
    119     kParsePathTestDimension = 500
    120 };
    121 
    122 DEF_SIMPLE_GM(parsedpaths, canvas, kParsePathTestDimension, kParsePathTestDimension) {
    123 #if GENERATE_SVG_REFERENCE
    124     FILE* file = sk_fopen("svgout.htm", kWrite_SkFILE_Flag);
    125     SkString str;
    126     str.printf("<svg width=\"%d\" height=\"%d\">\n", kParsePathTestDimension,
    127             kParsePathTestDimension);
    128     sk_fwrite(str.c_str(), str.size(), file);
    129 #endif
    130     SkRandom rand;
    131     SkPaint paint;
    132     paint.setAntiAlias(true);
    133     for (int xStart = 0; xStart < kParsePathTestDimension; xStart +=  100) {
    134         canvas->save();
    135         for (int yStart = 0; yStart < kParsePathTestDimension; yStart += 100) {
    136 #if GENERATE_SVG_REFERENCE
    137             str.printf("<g transform='translate(%d,%d) scale(%d,%d)'>\n", xStart, yStart,
    138                 1, 1);
    139             sk_fwrite(str.c_str(), str.size(), file);
    140             str.printf("<clipPath id='clip_%d_%d'>\n", xStart, yStart);
    141             sk_fwrite(str.c_str(), str.size(), file);
    142             str.printf("<rect width='100' height='100' x='0' y='0'></rect>\n");
    143             sk_fwrite(str.c_str(), str.size(), file);
    144             str.printf("</clipPath>\n");
    145             sk_fwrite(str.c_str(), str.size(), file);
    146 #endif
    147             int count = 3;
    148             do {
    149                 SkPath path;
    150                 SkString spec;
    151                 uint32_t y = rand.nextRangeU(30, 70);
    152                 uint32_t x = rand.nextRangeU(30, 70);
    153                 spec.printf("M %d,%d\n", x, y);
    154                 uint32_t count = rand.nextRangeU(0, 10);
    155                 for (uint32_t i = 0; i < count; ++i) {
    156                     spec.append(MakeRandomParsePathPiece(&rand));
    157                 }
    158                 SkAssertResult(SkParsePath::FromSVGString(spec.c_str(), &path));
    159                 paint.setColor(rand.nextU());
    160                 canvas->save();
    161                 canvas->clipRect(SkRect::MakeIWH(100, 100));
    162                 canvas->drawPath(path, paint);
    163                 canvas->restore();
    164 #if GENERATE_SVG_REFERENCE
    165                 str.printf("<path d='\n");
    166                 sk_fwrite(str.c_str(), str.size(), file);
    167                 sk_fwrite(spec.c_str(), spec.size(), file);
    168                 str.printf("\n' fill='#%06x' fill-opacity='%g'", paint.getColor() & 0xFFFFFF,
    169                         paint.getAlpha() / 255.f);
    170                 sk_fwrite(str.c_str(), str.size(), file);
    171                 str.printf(" clip-path='url(#clip_%d_%d)'/>\n", xStart, yStart);
    172                 sk_fwrite(str.c_str(), str.size(), file);
    173 #endif
    174             } while (--count > 0);
    175 #if GENERATE_SVG_REFERENCE
    176             str.printf("</g>\n");
    177             sk_fwrite(str.c_str(), str.size(), file);
    178 #endif
    179             canvas->translate(0, 100);
    180         }
    181         canvas->restore();
    182         canvas->translate(100, 0);
    183     }
    184 #if GENERATE_SVG_REFERENCE
    185     const char trailer[] = "</svg>\n";
    186     sk_fwrite(trailer, sizeof(trailer) - 1, file);
    187     sk_fclose(file);
    188 #endif
    189 }
    190 
    191 DEF_SIMPLE_GM(bug593049, canvas, 300, 300) {
    192     canvas->translate(111, 0);
    193 
    194     SkPath p;
    195     p.moveTo(-43.44464063610148f, 79.43535936389853f);
    196     const SkScalar yOffset = 122.88f;
    197     const SkScalar radius = 61.44f;
    198     SkRect oval = SkRect::MakeXYWH(-radius, yOffset - radius, 2 * radius, 2 * radius);
    199     p.arcTo(oval, 1.25f * 180, .5f * 180, false);
    200 
    201     SkPaint paint;
    202     paint.setStyle(SkPaint::kStroke_Style);
    203     paint.setStrokeCap(SkPaint::kRound_Cap);
    204     paint.setStrokeWidth(15.36f);
    205 
    206     canvas->drawPath(p, paint);
    207 }
    208 
    209 #include "SkDashPathEffect.h"
    210 #include "SkPathMeasure.h"
    211 
    212 DEF_SIMPLE_GM(bug583299, canvas, 300, 300) {
    213   const char* d="M60,60 A50,50 0 0 0 160,60 A50,50 0 0 0 60,60z";
    214   SkPaint p;
    215   p.setStyle(SkPaint::kStroke_Style);
    216   p.setStrokeWidth(100);
    217   p.setAntiAlias(true);
    218   p.setColor(0xFF008200);
    219   p.setStrokeCap(SkPaint::kSquare_Cap);
    220   SkPath path;
    221   SkParsePath::FromSVGString(d, &path);
    222   SkPathMeasure meas(path, false);
    223   SkScalar length = meas.getLength();
    224   SkScalar intervals[] = {0, length };
    225   int intervalCount = (int) SK_ARRAY_COUNT(intervals);
    226   p.setPathEffect(SkDashPathEffect::Make(intervals, intervalCount, 0));
    227   canvas->drawPath(path, p);
    228 }
    229