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 #include "gm.h" 8 #include "SkCanvas.h" 9 #include "SkPaint.h" 10 #include "SkRandom.h" 11 12 // skbug.com/1316 shows that this cubic, when slightly clipped, creates big 13 // (incorrect) changes to its control points. 14 class ClippedCubicGM : public skiagm::GM { 15 public: 16 ClippedCubicGM() {} 17 18 protected: 19 SkString onShortName() { 20 return SkString("clippedcubic"); 21 } 22 23 SkISize onISize() { return SkISize::Make(1240, 390); } 24 25 virtual void onDraw(SkCanvas* canvas) { 26 SkPath path; 27 path.moveTo(0, 0); 28 path.cubicTo(140, 150, 40, 10, 170, 150); 29 30 SkPaint paint; 31 SkRect bounds = path.getBounds(); 32 33 for (SkScalar dy = -1; dy <= 1; dy += 1) { 34 canvas->save(); 35 for (SkScalar dx = -1; dx <= 1; dx += 1) { 36 canvas->save(); 37 canvas->clipRect(bounds); 38 canvas->translate(dx, dy); 39 canvas->drawPath(path, paint); 40 canvas->restore(); 41 42 canvas->translate(bounds.width(), 0); 43 } 44 canvas->restore(); 45 canvas->translate(0, bounds.height()); 46 } 47 } 48 49 private: 50 typedef skiagm::GM INHERITED; 51 }; 52 53 class CubicPathGM : public skiagm::GM { 54 public: 55 CubicPathGM() {} 56 57 protected: 58 SkString onShortName() { 59 return SkString("cubicpath"); 60 } 61 62 SkISize onISize() { return SkISize::Make(1240, 390); } 63 64 void drawPath(SkPath& path,SkCanvas* canvas,SkColor color, 65 const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join, 66 SkPaint::Style style, SkPath::FillType fill, 67 SkScalar strokeWidth) { 68 path.setFillType(fill); 69 SkPaint paint; 70 paint.setStrokeCap(cap); 71 paint.setStrokeWidth(strokeWidth); 72 paint.setStrokeJoin(join); 73 paint.setColor(color); 74 paint.setStyle(style); 75 canvas->save(); 76 canvas->clipRect(clip); 77 canvas->drawPath(path, paint); 78 canvas->restore(); 79 } 80 81 virtual void onDraw(SkCanvas* canvas) { 82 struct FillAndName { 83 SkPath::FillType fFill; 84 const char* fName; 85 }; 86 static const FillAndName gFills[] = { 87 {SkPath::kWinding_FillType, "Winding"}, 88 {SkPath::kEvenOdd_FillType, "Even / Odd"}, 89 {SkPath::kInverseWinding_FillType, "Inverse Winding"}, 90 {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"}, 91 }; 92 struct StyleAndName { 93 SkPaint::Style fStyle; 94 const char* fName; 95 }; 96 static const StyleAndName gStyles[] = { 97 {SkPaint::kFill_Style, "Fill"}, 98 {SkPaint::kStroke_Style, "Stroke"}, 99 {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"}, 100 }; 101 struct CapAndName { 102 SkPaint::Cap fCap; 103 SkPaint::Join fJoin; 104 const char* fName; 105 }; 106 static const CapAndName gCaps[] = { 107 {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"}, 108 {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"}, 109 {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"} 110 }; 111 struct PathAndName { 112 SkPath fPath; 113 const char* fName; 114 }; 115 PathAndName path; 116 path.fPath.moveTo(25*SK_Scalar1, 10*SK_Scalar1); 117 path.fPath.cubicTo(40*SK_Scalar1, 20*SK_Scalar1, 118 60*SK_Scalar1, 20*SK_Scalar1, 119 75*SK_Scalar1, 10*SK_Scalar1); 120 path.fName = "moveTo-cubic"; 121 122 SkPaint titlePaint; 123 titlePaint.setColor(SK_ColorBLACK); 124 titlePaint.setAntiAlias(true); 125 titlePaint.setLCDRenderText(true); 126 titlePaint.setTextSize(15 * SK_Scalar1); 127 const char title[] = "Cubic Drawn Into Rectangle Clips With " 128 "Indicated Style, Fill and Linecaps, with stroke width 10"; 129 canvas->drawText(title, strlen(title), 130 20 * SK_Scalar1, 131 20 * SK_Scalar1, 132 titlePaint); 133 134 SkLCGRandom rand; 135 SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1); 136 canvas->save(); 137 canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1); 138 canvas->save(); 139 for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) { 140 if (0 < cap) { 141 canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0); 142 } 143 canvas->save(); 144 for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) { 145 if (0 < fill) { 146 canvas->translate(0, rect.height() + 40 * SK_Scalar1); 147 } 148 canvas->save(); 149 for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) { 150 if (0 < style) { 151 canvas->translate(rect.width() + 40 * SK_Scalar1, 0); 152 } 153 154 SkColor color = 0xff007000; 155 this->drawPath(path.fPath, canvas, color, rect, 156 gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle, 157 gFills[fill].fFill, SK_Scalar1*10); 158 159 SkPaint rectPaint; 160 rectPaint.setColor(SK_ColorBLACK); 161 rectPaint.setStyle(SkPaint::kStroke_Style); 162 rectPaint.setStrokeWidth(-1); 163 rectPaint.setAntiAlias(true); 164 canvas->drawRect(rect, rectPaint); 165 166 SkPaint labelPaint; 167 labelPaint.setColor(color); 168 labelPaint.setAntiAlias(true); 169 labelPaint.setLCDRenderText(true); 170 labelPaint.setTextSize(10 * SK_Scalar1); 171 canvas->drawText(gStyles[style].fName, 172 strlen(gStyles[style].fName), 173 0, rect.height() + 12 * SK_Scalar1, 174 labelPaint); 175 canvas->drawText(gFills[fill].fName, 176 strlen(gFills[fill].fName), 177 0, rect.height() + 24 * SK_Scalar1, 178 labelPaint); 179 canvas->drawText(gCaps[cap].fName, 180 strlen(gCaps[cap].fName), 181 0, rect.height() + 36 * SK_Scalar1, 182 labelPaint); 183 } 184 canvas->restore(); 185 } 186 canvas->restore(); 187 } 188 canvas->restore(); 189 canvas->restore(); 190 } 191 192 private: 193 typedef skiagm::GM INHERITED; 194 }; 195 196 class CubicClosePathGM : public skiagm::GM { 197 public: 198 CubicClosePathGM() {} 199 200 protected: 201 SkString onShortName() { 202 return SkString("cubicclosepath"); 203 } 204 205 SkISize onISize() { return SkISize::Make(1240, 390); } 206 207 void drawPath(SkPath& path,SkCanvas* canvas,SkColor color, 208 const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join, 209 SkPaint::Style style, SkPath::FillType fill, 210 SkScalar strokeWidth) { 211 path.setFillType(fill); 212 SkPaint paint; 213 paint.setStrokeCap(cap); 214 paint.setStrokeWidth(strokeWidth); 215 paint.setStrokeJoin(join); 216 paint.setColor(color); 217 paint.setStyle(style); 218 canvas->save(); 219 canvas->clipRect(clip); 220 canvas->drawPath(path, paint); 221 canvas->restore(); 222 } 223 224 virtual void onDraw(SkCanvas* canvas) { 225 struct FillAndName { 226 SkPath::FillType fFill; 227 const char* fName; 228 }; 229 static const FillAndName gFills[] = { 230 {SkPath::kWinding_FillType, "Winding"}, 231 {SkPath::kEvenOdd_FillType, "Even / Odd"}, 232 {SkPath::kInverseWinding_FillType, "Inverse Winding"}, 233 {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"}, 234 }; 235 struct StyleAndName { 236 SkPaint::Style fStyle; 237 const char* fName; 238 }; 239 static const StyleAndName gStyles[] = { 240 {SkPaint::kFill_Style, "Fill"}, 241 {SkPaint::kStroke_Style, "Stroke"}, 242 {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"}, 243 }; 244 struct CapAndName { 245 SkPaint::Cap fCap; 246 SkPaint::Join fJoin; 247 const char* fName; 248 }; 249 static const CapAndName gCaps[] = { 250 {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"}, 251 {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"}, 252 {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"} 253 }; 254 struct PathAndName { 255 SkPath fPath; 256 const char* fName; 257 }; 258 PathAndName path; 259 path.fPath.moveTo(25*SK_Scalar1, 10*SK_Scalar1); 260 path.fPath.cubicTo(40*SK_Scalar1, 20*SK_Scalar1, 261 60*SK_Scalar1, 20*SK_Scalar1, 262 75*SK_Scalar1, 10*SK_Scalar1); 263 path.fPath.close(); 264 path.fName = "moveTo-cubic-close"; 265 266 SkPaint titlePaint; 267 titlePaint.setColor(SK_ColorBLACK); 268 titlePaint.setAntiAlias(true); 269 titlePaint.setLCDRenderText(true); 270 titlePaint.setTextSize(15 * SK_Scalar1); 271 const char title[] = "Cubic Closed Drawn Into Rectangle Clips With " 272 "Indicated Style, Fill and Linecaps, with stroke width 10"; 273 canvas->drawText(title, strlen(title), 274 20 * SK_Scalar1, 275 20 * SK_Scalar1, 276 titlePaint); 277 278 SkLCGRandom rand; 279 SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1); 280 canvas->save(); 281 canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1); 282 canvas->save(); 283 for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) { 284 if (0 < cap) { 285 canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0); 286 } 287 canvas->save(); 288 for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) { 289 if (0 < fill) { 290 canvas->translate(0, rect.height() + 40 * SK_Scalar1); 291 } 292 canvas->save(); 293 for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) { 294 if (0 < style) { 295 canvas->translate(rect.width() + 40 * SK_Scalar1, 0); 296 } 297 298 SkColor color = 0xff007000; 299 this->drawPath(path.fPath, canvas, color, rect, 300 gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle, 301 gFills[fill].fFill, SK_Scalar1*10); 302 303 SkPaint rectPaint; 304 rectPaint.setColor(SK_ColorBLACK); 305 rectPaint.setStyle(SkPaint::kStroke_Style); 306 rectPaint.setStrokeWidth(-1); 307 rectPaint.setAntiAlias(true); 308 canvas->drawRect(rect, rectPaint); 309 310 SkPaint labelPaint; 311 labelPaint.setColor(color); 312 labelPaint.setAntiAlias(true); 313 labelPaint.setLCDRenderText(true); 314 labelPaint.setTextSize(10 * SK_Scalar1); 315 canvas->drawText(gStyles[style].fName, 316 strlen(gStyles[style].fName), 317 0, rect.height() + 12 * SK_Scalar1, 318 labelPaint); 319 canvas->drawText(gFills[fill].fName, 320 strlen(gFills[fill].fName), 321 0, rect.height() + 24 * SK_Scalar1, 322 labelPaint); 323 canvas->drawText(gCaps[cap].fName, 324 strlen(gCaps[cap].fName), 325 0, rect.height() + 36 * SK_Scalar1, 326 labelPaint); 327 } 328 canvas->restore(); 329 } 330 canvas->restore(); 331 } 332 canvas->restore(); 333 canvas->restore(); 334 } 335 336 private: 337 typedef skiagm::GM INHERITED; 338 }; 339 340 ////////////////////////////////////////////////////////////////////////////// 341 342 DEF_GM( return new CubicPathGM; ) 343 DEF_GM( return new CubicClosePathGM; ) 344 DEF_GM( return new ClippedCubicGM; ) 345