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