Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright 2013 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 SK_SUPPORT_GPU
     11 
     12 #include "GrContext.h"
     13 #include "GrPath.h"
     14 #include "GrShape.h"
     15 #include "SkBitmap.h"
     16 #include "SkCanvas.h"
     17 #include "SkColor.h"
     18 #include "SkPaint.h"
     19 #include "SkPath.h"
     20 #include "SkDashPathEffect.h"
     21 #include "SkRRect.h"
     22 #include "SkRect.h"
     23 #include "SkSurface.h"
     24 #include "Test.h"
     25 
     26 #include <initializer_list>
     27 
     28 static void test_drawPathEmpty(skiatest::Reporter*, SkCanvas* canvas) {
     29     // Filling an empty path should not crash.
     30     SkPaint paint;
     31     SkRect emptyRect = SkRect::MakeEmpty();
     32     canvas->drawRect(emptyRect, paint);
     33     canvas->drawPath(SkPath(), paint);
     34     canvas->drawOval(emptyRect, paint);
     35     canvas->drawRect(emptyRect, paint);
     36     canvas->drawRRect(SkRRect::MakeRect(emptyRect), paint);
     37 
     38     // Stroking an empty path should not crash.
     39     paint.setAntiAlias(true);
     40     paint.setStyle(SkPaint::kStroke_Style);
     41     paint.setColor(SK_ColorGRAY);
     42     paint.setStrokeWidth(SkIntToScalar(20));
     43     paint.setStrokeJoin(SkPaint::kRound_Join);
     44     canvas->drawRect(emptyRect, paint);
     45     canvas->drawPath(SkPath(), paint);
     46     canvas->drawOval(emptyRect, paint);
     47     canvas->drawRect(emptyRect, paint);
     48     canvas->drawRRect(SkRRect::MakeRect(emptyRect), paint);
     49 }
     50 
     51 static void fill_and_stroke(SkCanvas* canvas, const SkPath& p1, const SkPath& p2,
     52                             sk_sp<SkPathEffect> effect) {
     53     SkPaint paint;
     54     paint.setAntiAlias(true);
     55     paint.setPathEffect(effect);
     56 
     57     canvas->drawPath(p1, paint);
     58     canvas->drawPath(p2, paint);
     59 
     60     paint.setStyle(SkPaint::kStroke_Style);
     61     canvas->drawPath(p1, paint);
     62     canvas->drawPath(p2, paint);
     63 }
     64 
     65 static void test_drawSameRectOvals(skiatest::Reporter*, SkCanvas* canvas) {
     66     // Drawing ovals with similar bounds but different points order should not crash.
     67 
     68     SkPath oval1, oval2;
     69     const SkRect rect = SkRect::MakeWH(100, 50);
     70     oval1.addOval(rect, SkPath::kCW_Direction);
     71     oval2.addOval(rect, SkPath::kCCW_Direction);
     72 
     73     fill_and_stroke(canvas, oval1, oval2, nullptr);
     74 
     75     const SkScalar intervals[] = { 1, 1 };
     76     fill_and_stroke(canvas, oval1, oval2, SkDashPathEffect::Make(intervals, 2, 0));
     77 }
     78 
     79 DEF_GPUTEST_FOR_ALL_GL_CONTEXTS(GpuDrawPath, reporter, ctxInfo) {
     80     for (auto& test_func : { &test_drawPathEmpty, &test_drawSameRectOvals }) {
     81         for (auto& sampleCount : {0, 4, 16}) {
     82             SkImageInfo info = SkImageInfo::MakeN32Premul(255, 255);
     83             auto surface(
     84                 SkSurface::MakeRenderTarget(ctxInfo.grContext(), SkBudgeted::kNo, info,
     85                                             sampleCount, nullptr));
     86             if (!surface) {
     87                 continue;
     88             }
     89             test_func(reporter, surface->getCanvas());
     90         }
     91     }
     92 }
     93 
     94 DEF_GPUTEST(GrPathKeys, reporter, /*factory*/) {
     95     SkPaint strokePaint;
     96     strokePaint.setStyle(SkPaint::kStroke_Style);
     97     strokePaint.setStrokeWidth(10.f);
     98     GrStyle styles[] = {
     99         GrStyle::SimpleFill(),
    100         GrStyle::SimpleHairline(),
    101         GrStyle(strokePaint)
    102     };
    103 
    104     for (const GrStyle& style : styles) {
    105         // Keys should not ignore conic weights.
    106         SkPath path1, path2;
    107         SkPoint p0 = SkPoint::Make(100, 0);
    108         SkPoint p1 = SkPoint::Make(100, 100);
    109 
    110         path1.conicTo(p0, p1, .5f);
    111         path2.conicTo(p0, p1, .7f);
    112 
    113         GrUniqueKey key1, key2;
    114         // We expect these small paths to be keyed based on their data.
    115         bool isVolatile;
    116         GrPath::ComputeKey(GrShape(path1, GrStyle::SimpleFill()), &key1, &isVolatile);
    117         REPORTER_ASSERT(reporter, !isVolatile);
    118         REPORTER_ASSERT(reporter, key1.isValid());
    119         GrPath::ComputeKey(GrShape(path2, GrStyle::SimpleFill()), &key2, &isVolatile);
    120         REPORTER_ASSERT(reporter, !isVolatile);
    121         REPORTER_ASSERT(reporter, key1.isValid());
    122         REPORTER_ASSERT(reporter, key1 != key2);
    123         {
    124             GrUniqueKey tempKey;
    125             path1.setIsVolatile(true);
    126             GrPath::ComputeKey(GrShape(path1, style), &key1, &isVolatile);
    127             REPORTER_ASSERT(reporter, isVolatile);
    128             REPORTER_ASSERT(reporter, !tempKey.isValid());
    129         }
    130 
    131         // Ensure that recreating the GrShape doesn't change the key.
    132         {
    133             GrUniqueKey tempKey;
    134             GrPath::ComputeKey(GrShape(path2, GrStyle::SimpleFill()), &tempKey, &isVolatile);
    135             REPORTER_ASSERT(reporter, key2 == tempKey);
    136         }
    137 
    138         // Try a large path that is too big to be keyed off its data.
    139         SkPath path3;
    140         SkPath path4;
    141         for (int i = 0; i < 1000; ++i) {
    142             SkScalar s = SkIntToScalar(i);
    143             path3.conicTo(s, 3.f * s / 4, s + 1.f, s, 0.5f + s / 2000.f);
    144             path4.conicTo(s, 3.f * s / 4, s + 1.f, s, 0.3f + s / 2000.f);
    145         }
    146 
    147         GrUniqueKey key3, key4;
    148         // These aren't marked volatile and so should have keys
    149         GrPath::ComputeKey(GrShape(path3, style), &key3, &isVolatile);
    150         REPORTER_ASSERT(reporter, !isVolatile);
    151         REPORTER_ASSERT(reporter, key3.isValid());
    152         GrPath::ComputeKey(GrShape(path4, style), &key4, &isVolatile);
    153         REPORTER_ASSERT(reporter, !isVolatile);
    154         REPORTER_ASSERT(reporter, key4.isValid());
    155         REPORTER_ASSERT(reporter, key3 != key4);
    156 
    157         {
    158             GrUniqueKey tempKey;
    159             path3.setIsVolatile(true);
    160             GrPath::ComputeKey(GrShape(path3, style), &key1, &isVolatile);
    161             REPORTER_ASSERT(reporter, isVolatile);
    162             REPORTER_ASSERT(reporter, !tempKey.isValid());
    163         }
    164     }
    165 }
    166 
    167 #endif
    168