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. 14class ClippedCubicGM : public skiagm::GM { 15public: 16 ClippedCubicGM() {} 17 18protected: 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 53private: 54 typedef skiagm::GM INHERITED; 55}; 56 57class CubicPathGM : public skiagm::GM { 58public: 59 CubicPathGM() {} 60 61protected: 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 sk_tool_utils::set_portable_typeface(&titlePaint); 134 titlePaint.setLCDRenderText(true); 135 titlePaint.setTextSize(15 * SK_Scalar1); 136 const char title[] = "Cubic Drawn Into Rectangle Clips With " 137 "Indicated Style, Fill and Linecaps, with stroke width 10"; 138 canvas->drawText(title, strlen(title), 139 20 * SK_Scalar1, 140 20 * SK_Scalar1, 141 titlePaint); 142 143 SkLCGRandom rand; 144 SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1); 145 canvas->save(); 146 canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1); 147 canvas->save(); 148 for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) { 149 if (0 < cap) { 150 canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0); 151 } 152 canvas->save(); 153 for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) { 154 if (0 < fill) { 155 canvas->translate(0, rect.height() + 40 * SK_Scalar1); 156 } 157 canvas->save(); 158 for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) { 159 if (0 < style) { 160 canvas->translate(rect.width() + 40 * SK_Scalar1, 0); 161 } 162 163 SkColor color = 0xff007000; 164 this->drawPath(path.fPath, canvas, color, rect, 165 gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle, 166 gFills[fill].fFill, SK_Scalar1*10); 167 168 SkPaint rectPaint; 169 rectPaint.setColor(SK_ColorBLACK); 170 rectPaint.setStyle(SkPaint::kStroke_Style); 171 rectPaint.setStrokeWidth(-1); 172 rectPaint.setAntiAlias(true); 173 canvas->drawRect(rect, rectPaint); 174 175 SkPaint labelPaint; 176 labelPaint.setColor(color); 177 labelPaint.setAntiAlias(true); 178 sk_tool_utils::set_portable_typeface(&labelPaint); 179 labelPaint.setLCDRenderText(true); 180 labelPaint.setTextSize(10 * SK_Scalar1); 181 canvas->drawText(gStyles[style].fName, 182 strlen(gStyles[style].fName), 183 0, rect.height() + 12 * SK_Scalar1, 184 labelPaint); 185 canvas->drawText(gFills[fill].fName, 186 strlen(gFills[fill].fName), 187 0, rect.height() + 24 * SK_Scalar1, 188 labelPaint); 189 canvas->drawText(gCaps[cap].fName, 190 strlen(gCaps[cap].fName), 191 0, rect.height() + 36 * SK_Scalar1, 192 labelPaint); 193 } 194 canvas->restore(); 195 } 196 canvas->restore(); 197 } 198 canvas->restore(); 199 canvas->restore(); 200 } 201 202private: 203 typedef skiagm::GM INHERITED; 204}; 205 206class CubicClosePathGM : public skiagm::GM { 207public: 208 CubicClosePathGM() {} 209 210protected: 211 virtual uint32_t onGetFlags() const SK_OVERRIDE { 212 return kSkipTiled_Flag; 213 } 214 215 SkString onShortName() { 216 return SkString("cubicclosepath"); 217 } 218 219 SkISize onISize() { return SkISize::Make(1240, 390); } 220 221 void drawPath(SkPath& path,SkCanvas* canvas,SkColor color, 222 const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join, 223 SkPaint::Style style, SkPath::FillType fill, 224 SkScalar strokeWidth) { 225 path.setFillType(fill); 226 SkPaint paint; 227 paint.setStrokeCap(cap); 228 paint.setStrokeWidth(strokeWidth); 229 paint.setStrokeJoin(join); 230 paint.setColor(color); 231 paint.setStyle(style); 232 canvas->save(); 233 canvas->clipRect(clip); 234 canvas->drawPath(path, paint); 235 canvas->restore(); 236 } 237 238 virtual void onDraw(SkCanvas* canvas) { 239 struct FillAndName { 240 SkPath::FillType fFill; 241 const char* fName; 242 }; 243 static const FillAndName gFills[] = { 244 {SkPath::kWinding_FillType, "Winding"}, 245 {SkPath::kEvenOdd_FillType, "Even / Odd"}, 246 {SkPath::kInverseWinding_FillType, "Inverse Winding"}, 247 {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"}, 248 }; 249 struct StyleAndName { 250 SkPaint::Style fStyle; 251 const char* fName; 252 }; 253 static const StyleAndName gStyles[] = { 254 {SkPaint::kFill_Style, "Fill"}, 255 {SkPaint::kStroke_Style, "Stroke"}, 256 {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"}, 257 }; 258 struct CapAndName { 259 SkPaint::Cap fCap; 260 SkPaint::Join fJoin; 261 const char* fName; 262 }; 263 static const CapAndName gCaps[] = { 264 {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"}, 265 {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"}, 266 {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"} 267 }; 268 struct PathAndName { 269 SkPath fPath; 270 const char* fName; 271 }; 272 PathAndName path; 273 path.fPath.moveTo(25*SK_Scalar1, 10*SK_Scalar1); 274 path.fPath.cubicTo(40*SK_Scalar1, 20*SK_Scalar1, 275 60*SK_Scalar1, 20*SK_Scalar1, 276 75*SK_Scalar1, 10*SK_Scalar1); 277 path.fPath.close(); 278 path.fName = "moveTo-cubic-close"; 279 280 SkPaint titlePaint; 281 titlePaint.setColor(SK_ColorBLACK); 282 titlePaint.setAntiAlias(true); 283 sk_tool_utils::set_portable_typeface(&titlePaint); 284 titlePaint.setLCDRenderText(true); 285 titlePaint.setTextSize(15 * SK_Scalar1); 286 const char title[] = "Cubic Closed Drawn Into Rectangle Clips With " 287 "Indicated Style, Fill and Linecaps, with stroke width 10"; 288 canvas->drawText(title, strlen(title), 289 20 * SK_Scalar1, 290 20 * SK_Scalar1, 291 titlePaint); 292 293 SkLCGRandom rand; 294 SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1); 295 canvas->save(); 296 canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1); 297 canvas->save(); 298 for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) { 299 if (0 < cap) { 300 canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0); 301 } 302 canvas->save(); 303 for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) { 304 if (0 < fill) { 305 canvas->translate(0, rect.height() + 40 * SK_Scalar1); 306 } 307 canvas->save(); 308 for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) { 309 if (0 < style) { 310 canvas->translate(rect.width() + 40 * SK_Scalar1, 0); 311 } 312 313 SkColor color = 0xff007000; 314 this->drawPath(path.fPath, canvas, color, rect, 315 gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle, 316 gFills[fill].fFill, SK_Scalar1*10); 317 318 SkPaint rectPaint; 319 rectPaint.setColor(SK_ColorBLACK); 320 rectPaint.setStyle(SkPaint::kStroke_Style); 321 rectPaint.setStrokeWidth(-1); 322 rectPaint.setAntiAlias(true); 323 canvas->drawRect(rect, rectPaint); 324 325 SkPaint labelPaint; 326 labelPaint.setColor(color); 327 labelPaint.setAntiAlias(true); 328 sk_tool_utils::set_portable_typeface(&labelPaint); 329 labelPaint.setLCDRenderText(true); 330 labelPaint.setTextSize(10 * SK_Scalar1); 331 canvas->drawText(gStyles[style].fName, 332 strlen(gStyles[style].fName), 333 0, rect.height() + 12 * SK_Scalar1, 334 labelPaint); 335 canvas->drawText(gFills[fill].fName, 336 strlen(gFills[fill].fName), 337 0, rect.height() + 24 * SK_Scalar1, 338 labelPaint); 339 canvas->drawText(gCaps[cap].fName, 340 strlen(gCaps[cap].fName), 341 0, rect.height() + 36 * SK_Scalar1, 342 labelPaint); 343 } 344 canvas->restore(); 345 } 346 canvas->restore(); 347 } 348 canvas->restore(); 349 canvas->restore(); 350 } 351 352private: 353 typedef skiagm::GM INHERITED; 354}; 355 356////////////////////////////////////////////////////////////////////////////// 357 358DEF_GM( return new CubicPathGM; ) 359DEF_GM( return new CubicClosePathGM; ) 360DEF_GM( return new ClippedCubicGM; ) 361