1*c8dee2aaSAndroid Build Coastguard Worker /* 2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2013 Google Inc. 3*c8dee2aaSAndroid Build Coastguard Worker * 4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be 5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file. 6*c8dee2aaSAndroid Build Coastguard Worker */ 7*c8dee2aaSAndroid Build Coastguard Worker 8*c8dee2aaSAndroid Build Coastguard Worker #include "gm/gm.h" 9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h" 10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h" 11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPathBuilder.h" 12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h" 13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h" 14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h" 15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h" 16*c8dee2aaSAndroid Build Coastguard Worker 17*c8dee2aaSAndroid Build Coastguard Worker namespace skiagm { 18*c8dee2aaSAndroid Build Coastguard Worker 19*c8dee2aaSAndroid Build Coastguard Worker // This GM tests a grab-bag of non-closed paths. All these paths look like 20*c8dee2aaSAndroid Build Coastguard Worker // closed rects, but they don't call path.close(). Depending on the stroke 21*c8dee2aaSAndroid Build Coastguard Worker // settings these slightly different paths give widely different results. 22*c8dee2aaSAndroid Build Coastguard Worker class NonClosedPathsGM: public GM { 23*c8dee2aaSAndroid Build Coastguard Worker public: NonClosedPathsGM()24*c8dee2aaSAndroid Build Coastguard Worker NonClosedPathsGM() {} 25*c8dee2aaSAndroid Build Coastguard Worker 26*c8dee2aaSAndroid Build Coastguard Worker enum ClosureType { 27*c8dee2aaSAndroid Build Coastguard Worker TotallyNonClosed, // The last point doesn't coincide with the first one in the contour. 28*c8dee2aaSAndroid Build Coastguard Worker // The path looks not closed at all. 29*c8dee2aaSAndroid Build Coastguard Worker 30*c8dee2aaSAndroid Build Coastguard Worker FakeCloseCorner, // The last point coincides with the first one at a corner. 31*c8dee2aaSAndroid Build Coastguard Worker // The path looks closed, but final rendering has 2 ends with cap. 32*c8dee2aaSAndroid Build Coastguard Worker 33*c8dee2aaSAndroid Build Coastguard Worker FakeCloseMiddle, // The last point coincides with the first one in the middle of a line. 34*c8dee2aaSAndroid Build Coastguard Worker // The path looks closed, and the final rendering looks closed too. 35*c8dee2aaSAndroid Build Coastguard Worker 36*c8dee2aaSAndroid Build Coastguard Worker kClosureTypeCount 37*c8dee2aaSAndroid Build Coastguard Worker }; 38*c8dee2aaSAndroid Build Coastguard Worker 39*c8dee2aaSAndroid Build Coastguard Worker protected: getName() const40*c8dee2aaSAndroid Build Coastguard Worker SkString getName() const override { return SkString("nonclosedpaths"); } 41*c8dee2aaSAndroid Build Coastguard Worker 42*c8dee2aaSAndroid Build Coastguard Worker // 12 * 18 + 3 cases, every case is 100 * 100 pixels. getISize()43*c8dee2aaSAndroid Build Coastguard Worker SkISize getISize() override { return SkISize::Make(1220, 1920); } 44*c8dee2aaSAndroid Build Coastguard Worker 45*c8dee2aaSAndroid Build Coastguard Worker // Use rect-like geometry for non-closed path, for right angles make it 46*c8dee2aaSAndroid Build Coastguard Worker // easier to show the visual difference of lineCap and lineJoin. MakePath(ClosureType type)47*c8dee2aaSAndroid Build Coastguard Worker static SkPath MakePath(ClosureType type) { 48*c8dee2aaSAndroid Build Coastguard Worker SkPathBuilder path; 49*c8dee2aaSAndroid Build Coastguard Worker if (FakeCloseMiddle == type) { 50*c8dee2aaSAndroid Build Coastguard Worker path.moveTo(30, 50); 51*c8dee2aaSAndroid Build Coastguard Worker path.lineTo(30, 30); 52*c8dee2aaSAndroid Build Coastguard Worker } else { 53*c8dee2aaSAndroid Build Coastguard Worker path.moveTo(30, 30); 54*c8dee2aaSAndroid Build Coastguard Worker } 55*c8dee2aaSAndroid Build Coastguard Worker path.lineTo(70, 30); 56*c8dee2aaSAndroid Build Coastguard Worker path.lineTo(70, 70); 57*c8dee2aaSAndroid Build Coastguard Worker path.lineTo(30, 70); 58*c8dee2aaSAndroid Build Coastguard Worker path.lineTo(30, 50); 59*c8dee2aaSAndroid Build Coastguard Worker if (FakeCloseCorner == type) { 60*c8dee2aaSAndroid Build Coastguard Worker path.lineTo(30, 30); 61*c8dee2aaSAndroid Build Coastguard Worker } 62*c8dee2aaSAndroid Build Coastguard Worker return path.detach(); 63*c8dee2aaSAndroid Build Coastguard Worker } 64*c8dee2aaSAndroid Build Coastguard Worker 65*c8dee2aaSAndroid Build Coastguard Worker // Set the location for the current test on the canvas SetLocation(SkCanvas * canvas,int counter,int lineNum)66*c8dee2aaSAndroid Build Coastguard Worker static void SetLocation(SkCanvas* canvas, int counter, int lineNum) { 67*c8dee2aaSAndroid Build Coastguard Worker SkScalar x = SK_Scalar1 * 100 * (counter % lineNum) + 10 + SK_Scalar1 / 4; 68*c8dee2aaSAndroid Build Coastguard Worker SkScalar y = SK_Scalar1 * 100 * (counter / lineNum) + 10 + 3 * SK_Scalar1 / 4; 69*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(x, y); 70*c8dee2aaSAndroid Build Coastguard Worker } 71*c8dee2aaSAndroid Build Coastguard Worker onDraw(SkCanvas * canvas)72*c8dee2aaSAndroid Build Coastguard Worker void onDraw(SkCanvas* canvas) override { 73*c8dee2aaSAndroid Build Coastguard Worker // Stroke widths are: 74*c8dee2aaSAndroid Build Coastguard Worker // 0(may use hairline rendering), 10(common case for stroke-style) 75*c8dee2aaSAndroid Build Coastguard Worker // 40 and 50(>= geometry width/height, make the contour filled in fact) 76*c8dee2aaSAndroid Build Coastguard Worker constexpr int kStrokeWidth[] = {0, 10, 40, 50}; 77*c8dee2aaSAndroid Build Coastguard Worker int numWidths = std::size(kStrokeWidth); 78*c8dee2aaSAndroid Build Coastguard Worker 79*c8dee2aaSAndroid Build Coastguard Worker constexpr SkPaint::Style kStyle[] = { 80*c8dee2aaSAndroid Build Coastguard Worker SkPaint::kStroke_Style, SkPaint::kStrokeAndFill_Style 81*c8dee2aaSAndroid Build Coastguard Worker }; 82*c8dee2aaSAndroid Build Coastguard Worker 83*c8dee2aaSAndroid Build Coastguard Worker constexpr SkPaint::Cap kCap[] = { 84*c8dee2aaSAndroid Build Coastguard Worker SkPaint::kButt_Cap, SkPaint::kRound_Cap, SkPaint::kSquare_Cap 85*c8dee2aaSAndroid Build Coastguard Worker }; 86*c8dee2aaSAndroid Build Coastguard Worker 87*c8dee2aaSAndroid Build Coastguard Worker constexpr SkPaint::Join kJoin[] = { 88*c8dee2aaSAndroid Build Coastguard Worker SkPaint::kMiter_Join, SkPaint::kRound_Join, SkPaint::kBevel_Join 89*c8dee2aaSAndroid Build Coastguard Worker }; 90*c8dee2aaSAndroid Build Coastguard Worker 91*c8dee2aaSAndroid Build Coastguard Worker constexpr ClosureType kType[] = { 92*c8dee2aaSAndroid Build Coastguard Worker TotallyNonClosed, FakeCloseCorner, FakeCloseMiddle 93*c8dee2aaSAndroid Build Coastguard Worker }; 94*c8dee2aaSAndroid Build Coastguard Worker 95*c8dee2aaSAndroid Build Coastguard Worker int counter = 0; 96*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint; 97*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true); 98*c8dee2aaSAndroid Build Coastguard Worker 99*c8dee2aaSAndroid Build Coastguard Worker // For stroke style painter and fill-and-stroke style painter 100*c8dee2aaSAndroid Build Coastguard Worker for (size_t type = 0; type < kClosureTypeCount; ++type) { 101*c8dee2aaSAndroid Build Coastguard Worker for (size_t style = 0; style < std::size(kStyle); ++style) { 102*c8dee2aaSAndroid Build Coastguard Worker for (size_t cap = 0; cap < std::size(kCap); ++cap) { 103*c8dee2aaSAndroid Build Coastguard Worker for (size_t join = 0; join < std::size(kJoin); ++join) { 104*c8dee2aaSAndroid Build Coastguard Worker for (int width = 0; width < numWidths; ++width) { 105*c8dee2aaSAndroid Build Coastguard Worker canvas->save(); 106*c8dee2aaSAndroid Build Coastguard Worker SetLocation(canvas, counter, SkPaint::kJoinCount * numWidths); 107*c8dee2aaSAndroid Build Coastguard Worker 108*c8dee2aaSAndroid Build Coastguard Worker SkPath path = MakePath(kType[type]); 109*c8dee2aaSAndroid Build Coastguard Worker 110*c8dee2aaSAndroid Build Coastguard Worker paint.setStyle(kStyle[style]); 111*c8dee2aaSAndroid Build Coastguard Worker paint.setStrokeCap(kCap[cap]); 112*c8dee2aaSAndroid Build Coastguard Worker paint.setStrokeJoin(kJoin[join]); 113*c8dee2aaSAndroid Build Coastguard Worker paint.setStrokeWidth(SkIntToScalar(kStrokeWidth[width])); 114*c8dee2aaSAndroid Build Coastguard Worker 115*c8dee2aaSAndroid Build Coastguard Worker canvas->drawPath(path, paint); 116*c8dee2aaSAndroid Build Coastguard Worker canvas->restore(); 117*c8dee2aaSAndroid Build Coastguard Worker ++counter; 118*c8dee2aaSAndroid Build Coastguard Worker } 119*c8dee2aaSAndroid Build Coastguard Worker } 120*c8dee2aaSAndroid Build Coastguard Worker } 121*c8dee2aaSAndroid Build Coastguard Worker } 122*c8dee2aaSAndroid Build Coastguard Worker } 123*c8dee2aaSAndroid Build Coastguard Worker 124*c8dee2aaSAndroid Build Coastguard Worker // For fill style painter 125*c8dee2aaSAndroid Build Coastguard Worker paint.setStyle(SkPaint::kFill_Style); 126*c8dee2aaSAndroid Build Coastguard Worker for (size_t type = 0; type < kClosureTypeCount; ++type) { 127*c8dee2aaSAndroid Build Coastguard Worker canvas->save(); 128*c8dee2aaSAndroid Build Coastguard Worker SetLocation(canvas, counter, SkPaint::kJoinCount * numWidths); 129*c8dee2aaSAndroid Build Coastguard Worker 130*c8dee2aaSAndroid Build Coastguard Worker SkPath path = MakePath(kType[type]); 131*c8dee2aaSAndroid Build Coastguard Worker 132*c8dee2aaSAndroid Build Coastguard Worker canvas->drawPath(path, paint); 133*c8dee2aaSAndroid Build Coastguard Worker canvas->restore(); 134*c8dee2aaSAndroid Build Coastguard Worker ++counter; 135*c8dee2aaSAndroid Build Coastguard Worker } 136*c8dee2aaSAndroid Build Coastguard Worker } 137*c8dee2aaSAndroid Build Coastguard Worker 138*c8dee2aaSAndroid Build Coastguard Worker private: 139*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = GM; 140*c8dee2aaSAndroid Build Coastguard Worker }; 141*c8dee2aaSAndroid Build Coastguard Worker 142*c8dee2aaSAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////// 143*c8dee2aaSAndroid Build Coastguard Worker 144*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new NonClosedPathsGM;) 145*c8dee2aaSAndroid Build Coastguard Worker 146*c8dee2aaSAndroid Build Coastguard Worker } // namespace skiagm 147