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