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 "GrStrokeInfo.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
28static 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
51static void fill_and_stroke(SkCanvas* canvas, const SkPath& p1, const SkPath& p2,
52                            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
65static 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    SkAutoTUnref<SkPathEffect> dashEffect(SkDashPathEffect::Create(intervals, 2, 0));
77    fill_and_stroke(canvas, oval1, oval2, dashEffect);
78}
79
80DEF_GPUTEST_FOR_ALL_CONTEXTS(GpuDrawPath, reporter, context) {
81    for (auto& test_func : { &test_drawPathEmpty, &test_drawSameRectOvals }) {
82        for (auto& sampleCount : {0, 4, 16}) {
83            SkImageInfo info = SkImageInfo::MakeN32Premul(255, 255);
84            SkAutoTUnref<SkSurface> surface(
85                SkSurface::NewRenderTarget(context, SkBudgeted::kNo, info,
86                                           sampleCount, nullptr));
87            if (!surface) {
88                continue;
89            }
90            test_func(reporter, surface->getCanvas());
91        }
92    }
93}
94
95DEF_GPUTEST(GrPathKeys, reporter, /*factory*/) {
96    // Keys should not ignore conic weights.
97    SkPath path1, path2;
98    path1.setIsVolatile(true);
99    path2.setIsVolatile(true);
100    SkPoint p0 = SkPoint::Make(100, 0);
101    SkPoint p1 = SkPoint::Make(100, 100);
102
103    path1.conicTo(p0, p1, .5f);
104    path2.conicTo(p0, p1, .7f);
105
106    bool isVolatile;
107    GrUniqueKey key1, key2;
108    GrStrokeInfo stroke(SkStrokeRec::kFill_InitStyle);
109    GrPath::ComputeKey(path1, stroke, &key1, &isVolatile);
110    GrPath::ComputeKey(path2, stroke, &key2, &isVolatile);
111    REPORTER_ASSERT(reporter, key1 != key2);
112}
113
114#endif
115