xref: /third_party/skia/tests/EmptyPathTest.cpp (revision cb93a386)
1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2011 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "include/core/SkBitmap.h"
9cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h"
10cb93a386Sopenharmony_ci#include "include/core/SkPath.h"
11cb93a386Sopenharmony_ci#include "tests/Test.h"
12cb93a386Sopenharmony_ci
13cb93a386Sopenharmony_ci#define DIMENSION   32
14cb93a386Sopenharmony_ci
15cb93a386Sopenharmony_cistatic void drawAndTest(skiatest::Reporter* reporter, const SkPath& path,
16cb93a386Sopenharmony_ci                        const SkPaint& paint, bool shouldDraw) {
17cb93a386Sopenharmony_ci    SkBitmap bm;
18cb93a386Sopenharmony_ci    bm.allocN32Pixels(DIMENSION, DIMENSION);
19cb93a386Sopenharmony_ci    SkASSERT(DIMENSION*4 == bm.rowBytes()); // ensure no padding on each row
20cb93a386Sopenharmony_ci    bm.eraseColor(SK_ColorTRANSPARENT);
21cb93a386Sopenharmony_ci
22cb93a386Sopenharmony_ci    SkCanvas canvas(bm);
23cb93a386Sopenharmony_ci    SkPaint p(paint);
24cb93a386Sopenharmony_ci    p.setColor(SK_ColorWHITE);
25cb93a386Sopenharmony_ci
26cb93a386Sopenharmony_ci    canvas.drawPath(path, p);
27cb93a386Sopenharmony_ci
28cb93a386Sopenharmony_ci    size_t count = DIMENSION * DIMENSION;
29cb93a386Sopenharmony_ci    const SkPMColor* ptr = bm.getAddr32(0, 0);
30cb93a386Sopenharmony_ci
31cb93a386Sopenharmony_ci    SkPMColor andValue = ~0U;
32cb93a386Sopenharmony_ci    SkPMColor orValue = 0;
33cb93a386Sopenharmony_ci    for (size_t i = 0; i < count; ++i) {
34cb93a386Sopenharmony_ci        SkPMColor c = ptr[i];
35cb93a386Sopenharmony_ci        andValue &= c;
36cb93a386Sopenharmony_ci        orValue |= c;
37cb93a386Sopenharmony_ci    }
38cb93a386Sopenharmony_ci
39cb93a386Sopenharmony_ci    // success means we drew everywhere or nowhere (depending on shouldDraw)
40cb93a386Sopenharmony_ci    bool success = shouldDraw ? (~0U == andValue) : (0 == orValue);
41cb93a386Sopenharmony_ci
42cb93a386Sopenharmony_ci    if (!success) {
43cb93a386Sopenharmony_ci        const char* str;
44cb93a386Sopenharmony_ci        if (shouldDraw) {
45cb93a386Sopenharmony_ci            str = "Path expected to draw everywhere, but didn't. ";
46cb93a386Sopenharmony_ci        } else {
47cb93a386Sopenharmony_ci            str = "Path expected to draw nowhere, but did. ";
48cb93a386Sopenharmony_ci        }
49cb93a386Sopenharmony_ci        ERRORF(reporter, "%s style[%d] cap[%d] join[%d] antialias[%d]"
50cb93a386Sopenharmony_ci               " filltype[%d] ptcount[%d]", str, paint.getStyle(),
51cb93a386Sopenharmony_ci               paint.getStrokeCap(), paint.getStrokeJoin(),
52cb93a386Sopenharmony_ci               paint.isAntiAlias(), path.getFillType(), path.countPoints());
53cb93a386Sopenharmony_ci// uncomment this if you want to step in to see the failure
54cb93a386Sopenharmony_ci//        canvas.drawPath(path, p);
55cb93a386Sopenharmony_ci    }
56cb93a386Sopenharmony_ci}
57cb93a386Sopenharmony_ci
58cb93a386Sopenharmony_cienum DrawCaps {
59cb93a386Sopenharmony_ci    kDontDrawCaps,
60cb93a386Sopenharmony_ci    kDrawCaps
61cb93a386Sopenharmony_ci};
62cb93a386Sopenharmony_ci
63cb93a386Sopenharmony_cistatic void iter_paint(skiatest::Reporter* reporter, const SkPath& path, bool shouldDraw,
64cb93a386Sopenharmony_ci                       DrawCaps drawCaps) {
65cb93a386Sopenharmony_ci    static const SkPaint::Cap gCaps[] = {
66cb93a386Sopenharmony_ci        SkPaint::kButt_Cap,
67cb93a386Sopenharmony_ci        SkPaint::kRound_Cap,
68cb93a386Sopenharmony_ci        SkPaint::kSquare_Cap
69cb93a386Sopenharmony_ci    };
70cb93a386Sopenharmony_ci    static const SkPaint::Join gJoins[] = {
71cb93a386Sopenharmony_ci        SkPaint::kMiter_Join,
72cb93a386Sopenharmony_ci        SkPaint::kRound_Join,
73cb93a386Sopenharmony_ci        SkPaint::kBevel_Join
74cb93a386Sopenharmony_ci    };
75cb93a386Sopenharmony_ci    static const SkPaint::Style gStyles[] = {
76cb93a386Sopenharmony_ci        SkPaint::kFill_Style,
77cb93a386Sopenharmony_ci        SkPaint::kStroke_Style,
78cb93a386Sopenharmony_ci        SkPaint::kStrokeAndFill_Style
79cb93a386Sopenharmony_ci    };
80cb93a386Sopenharmony_ci    for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
81cb93a386Sopenharmony_ci        for (size_t join = 0; join < SK_ARRAY_COUNT(gJoins); ++join) {
82cb93a386Sopenharmony_ci            for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
83cb93a386Sopenharmony_ci                if (drawCaps && SkPaint::kButt_Cap != gCaps[cap]
84cb93a386Sopenharmony_ci                        && SkPaint::kFill_Style != gStyles[style]) {
85cb93a386Sopenharmony_ci                    continue;
86cb93a386Sopenharmony_ci                }
87cb93a386Sopenharmony_ci
88cb93a386Sopenharmony_ci                SkPaint paint;
89cb93a386Sopenharmony_ci                paint.setStrokeWidth(SkIntToScalar(10));
90cb93a386Sopenharmony_ci
91cb93a386Sopenharmony_ci                paint.setStrokeCap(gCaps[cap]);
92cb93a386Sopenharmony_ci                paint.setStrokeJoin(gJoins[join]);
93cb93a386Sopenharmony_ci                paint.setStyle(gStyles[style]);
94cb93a386Sopenharmony_ci
95cb93a386Sopenharmony_ci                paint.setAntiAlias(false);
96cb93a386Sopenharmony_ci                drawAndTest(reporter, path, paint, shouldDraw);
97cb93a386Sopenharmony_ci                paint.setAntiAlias(true);
98cb93a386Sopenharmony_ci                drawAndTest(reporter, path, paint, shouldDraw);
99cb93a386Sopenharmony_ci            }
100cb93a386Sopenharmony_ci        }
101cb93a386Sopenharmony_ci    }
102cb93a386Sopenharmony_ci}
103cb93a386Sopenharmony_ci
104cb93a386Sopenharmony_ci#define CX  (SkIntToScalar(DIMENSION) / 2)
105cb93a386Sopenharmony_ci#define CY  (SkIntToScalar(DIMENSION) / 2)
106cb93a386Sopenharmony_ci
107cb93a386Sopenharmony_cistatic void make_empty(SkPath*) {}
108cb93a386Sopenharmony_cistatic void make_M(SkPath* path) { path->moveTo(CX, CY); }
109cb93a386Sopenharmony_cistatic void make_MM(SkPath* path) { path->moveTo(CX, CY).moveTo(CX, CY); }
110cb93a386Sopenharmony_cistatic void make_MZM(SkPath* path) { path->moveTo(CX, CY).close().moveTo(CX, CY); }
111cb93a386Sopenharmony_cistatic void make_L(SkPath* path) { path->moveTo(CX, CY).lineTo(CX, CY); }
112cb93a386Sopenharmony_cistatic void make_Q(SkPath* path) { path->moveTo(CX, CY).quadTo(CX, CY, CX, CY); }
113cb93a386Sopenharmony_cistatic void make_C(SkPath* path) { path->moveTo(CX, CY).cubicTo(CX, CY, CX, CY, CX, CY); }
114cb93a386Sopenharmony_ci
115cb93a386Sopenharmony_ci/*  Two invariants are tested: How does an empty/degenerate path draw?
116cb93a386Sopenharmony_ci *  - if the path is drawn inverse, it should draw everywhere
117cb93a386Sopenharmony_ci *  - if the path is drawn non-inverse, it should draw nowhere
118cb93a386Sopenharmony_ci *
119cb93a386Sopenharmony_ci *  Things to iterate on:
120cb93a386Sopenharmony_ci *  - path (empty, degenerate line/quad/cubic w/ and w/o close
121cb93a386Sopenharmony_ci *  - paint style
122cb93a386Sopenharmony_ci *  - path filltype
123cb93a386Sopenharmony_ci *  - path stroke variants (e.g. caps, joins, width)
124cb93a386Sopenharmony_ci */
125cb93a386Sopenharmony_cistatic void test_emptydrawing(skiatest::Reporter* reporter) {
126cb93a386Sopenharmony_ci    static void (*gMakeProc[])(SkPath*) = {
127cb93a386Sopenharmony_ci        make_empty, make_M, make_MM, make_MZM, make_L, make_Q, make_C
128cb93a386Sopenharmony_ci    };
129cb93a386Sopenharmony_ci    static SkPathFillType gFills[] = {
130cb93a386Sopenharmony_ci        SkPathFillType::kWinding,
131cb93a386Sopenharmony_ci        SkPathFillType::kEvenOdd,
132cb93a386Sopenharmony_ci        SkPathFillType::kInverseWinding,
133cb93a386Sopenharmony_ci        SkPathFillType::kInverseEvenOdd
134cb93a386Sopenharmony_ci    };
135cb93a386Sopenharmony_ci    for (int doClose = 0; doClose < 2; ++doClose) {
136cb93a386Sopenharmony_ci        for  (size_t i = 0; i < SK_ARRAY_COUNT(gMakeProc); ++i) {
137cb93a386Sopenharmony_ci            SkPath path;
138cb93a386Sopenharmony_ci            gMakeProc[i](&path);
139cb93a386Sopenharmony_ci            if (doClose) {
140cb93a386Sopenharmony_ci                path.close();
141cb93a386Sopenharmony_ci            }
142cb93a386Sopenharmony_ci            /* zero length segments and close following moves draw round and square caps */
143cb93a386Sopenharmony_ci            bool allowCaps = make_L == gMakeProc[i] || make_Q == gMakeProc[i]
144cb93a386Sopenharmony_ci                    || make_C == gMakeProc[i] || make_MZM == gMakeProc[i];
145cb93a386Sopenharmony_ci            allowCaps |= SkToBool(doClose);
146cb93a386Sopenharmony_ci            for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
147cb93a386Sopenharmony_ci                path.setFillType(gFills[fill]);
148cb93a386Sopenharmony_ci                bool shouldDraw = path.isInverseFillType();
149cb93a386Sopenharmony_ci                iter_paint(reporter, path, shouldDraw, allowCaps ? kDrawCaps : kDontDrawCaps);
150cb93a386Sopenharmony_ci            }
151cb93a386Sopenharmony_ci        }
152cb93a386Sopenharmony_ci    }
153cb93a386Sopenharmony_ci}
154cb93a386Sopenharmony_ci
155cb93a386Sopenharmony_ciDEF_TEST(EmptyPath, reporter) {
156cb93a386Sopenharmony_ci    test_emptydrawing(reporter);
157cb93a386Sopenharmony_ci}
158