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