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