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 "gm/gm.h" 9 #include "include/core/SkCanvas.h" 10 #include "include/core/SkColor.h" 11 #include "include/core/SkPaint.h" 12 #include "include/core/SkPathBuilder.h" 13 #include "include/core/SkPoint.h" 14 #include "include/core/SkRect.h" 15 #include "include/core/SkScalar.h" 16 #include "include/core/SkSize.h" 17 #include "include/core/SkString.h" 18 #include "include/core/SkTypes.h" 19 #include "include/private/base/SkTArray.h" 20 #include "src/base/SkFloatBits.h" 21 22 using namespace skia_private; 23 24 class ConicPathsGM : public skiagm::GM { 25 protected: getName() const26 SkString getName() const override { return SkString("conicpaths"); } 27 getISize()28 SkISize getISize() override { return SkISize::Make(920, 960); } 29 append_path(Proc proc)30 template <typename Proc> void append_path(Proc proc) { 31 SkPathBuilder b; 32 proc(&b); 33 fPaths.push_back(b.detach()); 34 } 35 onOnceBeforeDraw()36 void onOnceBeforeDraw() override { 37 this->append_path([](SkPathBuilder* conicCircle) { 38 const SkScalar w = SkScalarSqrt(2)/2; 39 conicCircle->moveTo(0, 0); 40 conicCircle->conicTo(0, 50, 50, 50, w); 41 conicCircle->rConicTo(50, 0, 50, -50, w); 42 conicCircle->rConicTo(0, -50, -50, -50, w); 43 conicCircle->rConicTo(-50, 0, -50, 50, w); 44 }); 45 46 this->append_path([](SkPathBuilder* hyperbola) { 47 hyperbola->moveTo(0, 0); 48 hyperbola->conicTo(0, 100, 100, 100, 2); 49 }); 50 51 this->append_path([](SkPathBuilder* thinHyperbola) { 52 thinHyperbola->moveTo(0, 0); 53 thinHyperbola->conicTo(100, 100, 5, 0, 2); 54 }); 55 56 this->append_path([](SkPathBuilder* veryThinHyperbola) { 57 veryThinHyperbola->moveTo(0, 0); 58 veryThinHyperbola->conicTo(100, 100, 1, 0, 2); 59 }); 60 61 this->append_path([](SkPathBuilder* closedHyperbola) { 62 closedHyperbola->moveTo(0, 0); 63 closedHyperbola->conicTo(100, 100, 0, 0, 2); 64 }); 65 66 this->append_path([](SkPathBuilder* nearParabola) { 67 // using 1 as weight defaults to using quadTo 68 nearParabola->moveTo(0, 0); 69 nearParabola->conicTo(0, 100, 100, 100, 0.999f); 70 }); 71 72 this->append_path([](SkPathBuilder* thinEllipse) { 73 thinEllipse->moveTo(0, 0); 74 thinEllipse->conicTo(100, 100, 5, 0, SK_ScalarHalf); 75 }); 76 77 this->append_path([](SkPathBuilder* veryThinEllipse) { 78 veryThinEllipse->moveTo(0, 0); 79 veryThinEllipse->conicTo(100, 100, 1, 0, SK_ScalarHalf); 80 }); 81 82 this->append_path([](SkPathBuilder* closedEllipse) { 83 closedEllipse->moveTo(0, 0); 84 closedEllipse->conicTo(100, 100, 0, 0, SK_ScalarHalf); 85 }); 86 87 { 88 SkPathBuilder b; 89 const SkScalar w = SkScalarSqrt(2)/2; 90 b.moveTo(2.1e+11f, -1.05e+11f); 91 b.conicTo(2.1e+11f, 0, 1.05e+11f, 0, w); 92 b.conicTo(0, 0, 0, -1.05e+11f, w); 93 b.conicTo(0, -2.1e+11f, 1.05e+11f, -2.1e+11f, w); 94 b.conicTo(2.1e+11f, -2.1e+11f, 2.1e+11f, -1.05e+11f, w); 95 fGiantCircle = b.detach(); 96 } 97 } 98 drawGiantCircle(SkCanvas * canvas)99 void drawGiantCircle(SkCanvas* canvas) { 100 SkPaint paint; 101 canvas->drawPath(fGiantCircle, paint); 102 } 103 onDraw(SkCanvas * canvas)104 void onDraw(SkCanvas* canvas) override { 105 const SkAlpha kAlphaValue[] = { 0xFF, 0x40 }; 106 107 const SkScalar margin = 15; 108 canvas->translate(margin, margin); 109 110 SkPaint paint; 111 for (int p = 0; p < fPaths.size(); ++p) { 112 canvas->save(); 113 for (size_t a = 0; a < std::size(kAlphaValue); ++a) { 114 paint.setARGB(kAlphaValue[a], 0, 0, 0); 115 for (int aa = 0; aa < 2; ++aa) { 116 paint.setAntiAlias(SkToBool(aa)); 117 for (int fh = 0; fh < 2; ++fh) { 118 paint.setStroke(fh != 0); 119 120 const SkRect& bounds = fPaths[p].getBounds(); 121 canvas->save(); 122 canvas->translate(-bounds.fLeft, -bounds.fTop); 123 canvas->drawPath(fPaths[p], paint); 124 canvas->restore(); 125 126 canvas->translate(110, 0); 127 } 128 } 129 } 130 canvas->restore(); 131 canvas->translate(0, 110); 132 } 133 canvas->restore(); 134 135 this->drawGiantCircle(canvas); 136 } 137 138 private: 139 TArray<SkPath> fPaths; 140 SkPath fGiantCircle; 141 using INHERITED = skiagm::GM; 142 }; 143 DEF_GM(return new ConicPathsGM;) 144 145 ////////////////////////////////////////////////////////////////////////////// 146 147 /* arc should be on top of circle */ 148 DEF_SIMPLE_GM(arccirclegap, canvas, 250, 250) { 149 canvas->translate(50, 100); 150 SkPoint c = { 1052.5390625f, 506.8760978034711f }; 151 SkScalar radius = 1096.702150363923f; 152 SkPaint paint; 153 paint.setAntiAlias(true); 154 paint.setStroke(true); 155 canvas->drawCircle(c, radius, paint); 156 SkPath path = SkPathBuilder().moveTo(288.88884710654133f, -280.26680862609f) 157 .arcTo({0, 0}, {-39.00216443306411f, 400.6058925796476f}, radius) 158 .detach(); 159 paint.setColor(0xff007f00); 160 canvas->drawPath(path, paint); 161 } 162 163 /* circle should be antialiased */ 164 DEF_SIMPLE_GM(largecircle, canvas, 250, 250) { 165 canvas->translate(50, 100); 166 SkPoint c = { 1052.5390625f, 506.8760978034711f }; 167 SkScalar radius = 1096.702150363923f; 168 SkPaint paint; 169 paint.setAntiAlias(true); 170 paint.setStroke(true); 171 canvas->drawCircle(c, radius, paint); 172 } 173 174 /* ovals should not be blurry */ 175 DEF_SIMPLE_GM(largeovals, canvas, 250, 250) { 176 // Test EllipseOp 177 SkRect r = SkRect::MakeXYWH(-520, -520, 5000, 4000); 178 SkPaint paint; 179 paint.setAntiAlias(true); 180 paint.setStroke(true); 181 paint.setStrokeWidth(100); 182 canvas->drawOval(r, paint); 183 r.offset(-15, -15); 184 paint.setColor(SK_ColorDKGRAY); 185 // we use stroke and fill to avoid falling into the SimpleFill path 186 paint.setStyle(SkPaint::kStrokeAndFill_Style); 187 paint.setStrokeWidth(1); 188 canvas->drawOval(r, paint); 189 190 // Test DIEllipseOp 191 canvas->rotate(1.0f); 192 r.offset(55, 55); 193 paint.setColor(SK_ColorGRAY); 194 paint.setStroke(true); 195 paint.setStrokeWidth(100); 196 canvas->drawOval(r, paint); 197 r.offset(-15, -15); 198 paint.setColor(SK_ColorLTGRAY); 199 paint.setStyle(SkPaint::kStrokeAndFill_Style); 200 paint.setStrokeWidth(1); 201 canvas->drawOval(r, paint); 202 } 203 204 DEF_SIMPLE_GM(crbug_640176, canvas, 250, 250) { 205 SkPathBuilder path; 206 path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0 207 path.lineTo(SkBits2Float(0x42cfd89a), SkBits2Float(0xc2700000)); // 103.923f, -60 208 path.lineTo(SkBits2Float(0x42cfd899), SkBits2Float(0xc2700006)); // 103.923f, -60 209 path.conicTo(SkBits2Float(0x42f00000), SkBits2Float(0xc2009d9c), 210 SkBits2Float(0x42f00001), SkBits2Float(0x00000000), 211 SkBits2Float(0x3f7746ea)); // 120, -32.1539f, 120, 0, 0.965926f 212 213 SkPaint paint; 214 paint.setAntiAlias(true); 215 canvas->translate(125, 125); 216 canvas->drawPath(path.detach(), paint); 217 } 218