1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2011 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "gm/gm.h" 9cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 10cb93a386Sopenharmony_ci#include "include/core/SkColor.h" 11cb93a386Sopenharmony_ci#include "include/core/SkMatrix.h" 12cb93a386Sopenharmony_ci#include "include/core/SkPaint.h" 13cb93a386Sopenharmony_ci#include "include/core/SkPathBuilder.h" 14cb93a386Sopenharmony_ci#include "include/core/SkRect.h" 15cb93a386Sopenharmony_ci#include "include/core/SkScalar.h" 16cb93a386Sopenharmony_ci#include "include/core/SkSize.h" 17cb93a386Sopenharmony_ci#include "include/core/SkString.h" 18cb93a386Sopenharmony_ci#include "include/core/SkTypes.h" 19cb93a386Sopenharmony_ci#include "include/private/SkNoncopyable.h" 20cb93a386Sopenharmony_ci#include "include/private/SkTArray.h" 21cb93a386Sopenharmony_ci#include "include/utils/SkRandom.h" 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_cinamespace { 24cb93a386Sopenharmony_ci 25cb93a386Sopenharmony_ciclass SkDoOnce : SkNoncopyable { 26cb93a386Sopenharmony_cipublic: 27cb93a386Sopenharmony_ci SkDoOnce() { fDidOnce = false; } 28cb93a386Sopenharmony_ci 29cb93a386Sopenharmony_ci bool needToDo() const { return !fDidOnce; } 30cb93a386Sopenharmony_ci bool alreadyDone() const { return fDidOnce; } 31cb93a386Sopenharmony_ci void accomplished() { 32cb93a386Sopenharmony_ci SkASSERT(!fDidOnce); 33cb93a386Sopenharmony_ci fDidOnce = true; 34cb93a386Sopenharmony_ci } 35cb93a386Sopenharmony_ci 36cb93a386Sopenharmony_ciprivate: 37cb93a386Sopenharmony_ci bool fDidOnce; 38cb93a386Sopenharmony_ci}; 39cb93a386Sopenharmony_ci 40cb93a386Sopenharmony_ciclass ConvexPathsGM : public skiagm::GM { 41cb93a386Sopenharmony_ci SkDoOnce fOnce; 42cb93a386Sopenharmony_ci 43cb93a386Sopenharmony_ci void onOnceBeforeDraw() override { this->setBGColor(0xFF000000); } 44cb93a386Sopenharmony_ci 45cb93a386Sopenharmony_ci SkString onShortName() override { return SkString("convexpaths"); } 46cb93a386Sopenharmony_ci 47cb93a386Sopenharmony_ci 48cb93a386Sopenharmony_ci SkISize onISize() override { return {1200, 1100}; } 49cb93a386Sopenharmony_ci 50cb93a386Sopenharmony_ci void makePaths() { 51cb93a386Sopenharmony_ci if (fOnce.alreadyDone()) { 52cb93a386Sopenharmony_ci return; 53cb93a386Sopenharmony_ci } 54cb93a386Sopenharmony_ci fOnce.accomplished(); 55cb93a386Sopenharmony_ci 56cb93a386Sopenharmony_ci SkPathBuilder b; 57cb93a386Sopenharmony_ci fPaths.push_back(b.moveTo(0, 0) 58cb93a386Sopenharmony_ci .quadTo(50, 100, 0, 100) 59cb93a386Sopenharmony_ci .lineTo(0, 0) 60cb93a386Sopenharmony_ci .detach()); 61cb93a386Sopenharmony_ci 62cb93a386Sopenharmony_ci fPaths.push_back(b.moveTo(0, 50) 63cb93a386Sopenharmony_ci .quadTo(50, 0, 100, 50) 64cb93a386Sopenharmony_ci .quadTo(50, 100, 0, 50) 65cb93a386Sopenharmony_ci .detach()); 66cb93a386Sopenharmony_ci 67cb93a386Sopenharmony_ci fPaths.push_back(SkPath::Rect({0, 0, 100, 100}, SkPathDirection::kCW)); 68cb93a386Sopenharmony_ci fPaths.push_back(SkPath::Rect({0, 0, 100, 100}, SkPathDirection::kCCW)); 69cb93a386Sopenharmony_ci fPaths.push_back(SkPath::Circle(50, 50, 50, SkPathDirection::kCW)); 70cb93a386Sopenharmony_ci fPaths.push_back(SkPath::Oval(SkRect::MakeXYWH(0, 0, 50, 100), SkPathDirection::kCW)); 71cb93a386Sopenharmony_ci fPaths.push_back(SkPath::Oval(SkRect::MakeXYWH(0, 0, 100, 5), SkPathDirection::kCCW)); 72cb93a386Sopenharmony_ci fPaths.push_back(SkPath::Oval(SkRect::MakeXYWH(0, 0, 1, 100), SkPathDirection::kCCW)); 73cb93a386Sopenharmony_ci fPaths.push_back(SkPath::RRect(SkRRect::MakeRectXY({0, 0, 100, 100}, 40, 20), 74cb93a386Sopenharmony_ci SkPathDirection::kCW)); 75cb93a386Sopenharmony_ci 76cb93a386Sopenharmony_ci // large number of points 77cb93a386Sopenharmony_ci enum { 78cb93a386Sopenharmony_ci kLength = 100, 79cb93a386Sopenharmony_ci kPtsPerSide = (1 << 12), 80cb93a386Sopenharmony_ci }; 81cb93a386Sopenharmony_ci b.moveTo(0, 0); 82cb93a386Sopenharmony_ci for (int i = 1; i < kPtsPerSide; ++i) { // skip the first point due to moveTo. 83cb93a386Sopenharmony_ci b.lineTo(kLength * SkIntToScalar(i) / kPtsPerSide, 0); 84cb93a386Sopenharmony_ci } 85cb93a386Sopenharmony_ci for (int i = 0; i < kPtsPerSide; ++i) { 86cb93a386Sopenharmony_ci b.lineTo(kLength, kLength * SkIntToScalar(i) / kPtsPerSide); 87cb93a386Sopenharmony_ci } 88cb93a386Sopenharmony_ci for (int i = kPtsPerSide; i > 0; --i) { 89cb93a386Sopenharmony_ci b.lineTo(kLength * SkIntToScalar(i) / kPtsPerSide, kLength); 90cb93a386Sopenharmony_ci } 91cb93a386Sopenharmony_ci for (int i = kPtsPerSide; i > 0; --i) { 92cb93a386Sopenharmony_ci b.lineTo(0, kLength * SkIntToScalar(i) / kPtsPerSide); 93cb93a386Sopenharmony_ci } 94cb93a386Sopenharmony_ci fPaths.push_back(b.detach()); 95cb93a386Sopenharmony_ci 96cb93a386Sopenharmony_ci // shallow diagonals 97cb93a386Sopenharmony_ci fPaths.push_back(SkPath::Polygon({{0,0}, {100,1}, {98,100}, {3,96}}, false)); 98cb93a386Sopenharmony_ci 99cb93a386Sopenharmony_ci fPaths.push_back(b.arcTo(SkRect::MakeXYWH(0, 0, 50, 100), 25, 130, false) 100cb93a386Sopenharmony_ci .detach()); 101cb93a386Sopenharmony_ci 102cb93a386Sopenharmony_ci // cubics 103cb93a386Sopenharmony_ci fPaths.push_back(b.cubicTo( 1, 1, 10, 90, 0, 100).detach()); 104cb93a386Sopenharmony_ci fPaths.push_back(b.cubicTo(100, 50, 20, 100, 0, 0).detach()); 105cb93a386Sopenharmony_ci 106cb93a386Sopenharmony_ci // path that has a cubic with a repeated first control point and 107cb93a386Sopenharmony_ci // a repeated last control point. 108cb93a386Sopenharmony_ci fPaths.push_back(b.moveTo(10, 10) 109cb93a386Sopenharmony_ci .cubicTo(10, 10, 10, 0, 20, 0) 110cb93a386Sopenharmony_ci .lineTo(40, 0) 111cb93a386Sopenharmony_ci .cubicTo(40, 0, 50, 0, 50, 10) 112cb93a386Sopenharmony_ci .detach()); 113cb93a386Sopenharmony_ci 114cb93a386Sopenharmony_ci // path that has two cubics with repeated middle control points. 115cb93a386Sopenharmony_ci fPaths.push_back(b.moveTo(10, 10) 116cb93a386Sopenharmony_ci .cubicTo(10, 0, 10, 0, 20, 0) 117cb93a386Sopenharmony_ci .lineTo(40, 0) 118cb93a386Sopenharmony_ci .cubicTo(50, 0, 50, 0, 50, 10) 119cb93a386Sopenharmony_ci .detach()); 120cb93a386Sopenharmony_ci 121cb93a386Sopenharmony_ci // cubic where last three points are almost a line 122cb93a386Sopenharmony_ci fPaths.push_back(b.moveTo(0, 228.0f/8) 123cb93a386Sopenharmony_ci .cubicTo( 628.0f/ 8, 82.0f/8, 124cb93a386Sopenharmony_ci 1255.0f/ 8, 141.0f/8, 125cb93a386Sopenharmony_ci 1883.0f/ 8, 202.0f/8) 126cb93a386Sopenharmony_ci .detach()); 127cb93a386Sopenharmony_ci 128cb93a386Sopenharmony_ci // flat cubic where the at end point tangents both point outward. 129cb93a386Sopenharmony_ci fPaths.push_back(b.moveTo(10, 0) 130cb93a386Sopenharmony_ci .cubicTo(0, 1, 30, 1, 20, 0) 131cb93a386Sopenharmony_ci .detach()); 132cb93a386Sopenharmony_ci 133cb93a386Sopenharmony_ci // flat cubic where initial tangent is in, end tangent out 134cb93a386Sopenharmony_ci fPaths.push_back(b.moveTo(0, 0) 135cb93a386Sopenharmony_ci .cubicTo(10, 1, 30, 1, 20, 0) 136cb93a386Sopenharmony_ci .detach()); 137cb93a386Sopenharmony_ci 138cb93a386Sopenharmony_ci // flat cubic where initial tangent is out, end tangent in 139cb93a386Sopenharmony_ci fPaths.push_back(b.moveTo(10, 0) 140cb93a386Sopenharmony_ci .cubicTo(0, 1, 20, 1, 30, 0) 141cb93a386Sopenharmony_ci .detach()); 142cb93a386Sopenharmony_ci 143cb93a386Sopenharmony_ci // triangle where one edge is a degenerate quad 144cb93a386Sopenharmony_ci fPaths.push_back(b.moveTo(8.59375f, 45) 145cb93a386Sopenharmony_ci .quadTo(16.9921875f, 45, 146cb93a386Sopenharmony_ci 31.25f, 45) 147cb93a386Sopenharmony_ci .lineTo(100, 100) 148cb93a386Sopenharmony_ci .lineTo(8.59375f, 45) 149cb93a386Sopenharmony_ci .detach()); 150cb93a386Sopenharmony_ci 151cb93a386Sopenharmony_ci // triangle where one edge is a quad with a repeated point 152cb93a386Sopenharmony_ci fPaths.push_back(b.moveTo(0, 25) 153cb93a386Sopenharmony_ci .lineTo(50, 0) 154cb93a386Sopenharmony_ci .quadTo(50, 50, 50, 50) 155cb93a386Sopenharmony_ci .detach()); 156cb93a386Sopenharmony_ci 157cb93a386Sopenharmony_ci // triangle where one edge is a cubic with a 2x repeated point 158cb93a386Sopenharmony_ci fPaths.push_back(b.moveTo(0, 25) 159cb93a386Sopenharmony_ci .lineTo(50, 0) 160cb93a386Sopenharmony_ci .cubicTo(50, 0, 50, 50, 50, 50) 161cb93a386Sopenharmony_ci .detach()); 162cb93a386Sopenharmony_ci 163cb93a386Sopenharmony_ci // triangle where one edge is a quad with a nearly repeated point 164cb93a386Sopenharmony_ci fPaths.push_back(b.moveTo(0, 25) 165cb93a386Sopenharmony_ci .lineTo(50, 0) 166cb93a386Sopenharmony_ci .quadTo(50, 49.95f, 50, 50) 167cb93a386Sopenharmony_ci .detach()); 168cb93a386Sopenharmony_ci 169cb93a386Sopenharmony_ci // triangle where one edge is a cubic with a 3x nearly repeated point 170cb93a386Sopenharmony_ci fPaths.push_back(b.moveTo(0, 25) 171cb93a386Sopenharmony_ci .lineTo(50, 0) 172cb93a386Sopenharmony_ci .cubicTo(50, 49.95f, 50, 49.97f, 50, 50) 173cb93a386Sopenharmony_ci .detach()); 174cb93a386Sopenharmony_ci 175cb93a386Sopenharmony_ci // triangle where there is a point degenerate cubic at one corner 176cb93a386Sopenharmony_ci fPaths.push_back(b.moveTo(0, 25) 177cb93a386Sopenharmony_ci .lineTo(50, 0) 178cb93a386Sopenharmony_ci .lineTo(50, 50) 179cb93a386Sopenharmony_ci .cubicTo(50, 50, 50, 50, 50, 50) 180cb93a386Sopenharmony_ci .detach()); 181cb93a386Sopenharmony_ci 182cb93a386Sopenharmony_ci // point line 183cb93a386Sopenharmony_ci fPaths.push_back(SkPath::Line({50, 50}, {50, 50})); 184cb93a386Sopenharmony_ci 185cb93a386Sopenharmony_ci // point quad 186cb93a386Sopenharmony_ci fPaths.push_back(b.moveTo(50, 50) 187cb93a386Sopenharmony_ci .quadTo(50, 50, 50, 50) 188cb93a386Sopenharmony_ci .detach()); 189cb93a386Sopenharmony_ci 190cb93a386Sopenharmony_ci // point cubic 191cb93a386Sopenharmony_ci fPaths.push_back(b.moveTo(50, 50) 192cb93a386Sopenharmony_ci .cubicTo(50, 50, 50, 50, 50, 50) 193cb93a386Sopenharmony_ci .detach()); 194cb93a386Sopenharmony_ci 195cb93a386Sopenharmony_ci // moveTo only paths 196cb93a386Sopenharmony_ci fPaths.push_back(b.moveTo(0, 0) 197cb93a386Sopenharmony_ci .moveTo(0, 0) 198cb93a386Sopenharmony_ci .moveTo(1, 1) 199cb93a386Sopenharmony_ci .moveTo(1, 1) 200cb93a386Sopenharmony_ci .moveTo(10, 10) 201cb93a386Sopenharmony_ci .detach()); 202cb93a386Sopenharmony_ci 203cb93a386Sopenharmony_ci fPaths.push_back(b.moveTo(0, 0) 204cb93a386Sopenharmony_ci .moveTo(0, 0) 205cb93a386Sopenharmony_ci .detach()); 206cb93a386Sopenharmony_ci 207cb93a386Sopenharmony_ci // line degenerate 208cb93a386Sopenharmony_ci fPaths.push_back(b.lineTo(100, 100).detach()); 209cb93a386Sopenharmony_ci fPaths.push_back(b.quadTo(100, 100, 0, 0).detach()); 210cb93a386Sopenharmony_ci fPaths.push_back(b.quadTo(100, 100, 50, 50).detach()); 211cb93a386Sopenharmony_ci fPaths.push_back(b.quadTo(50, 50, 100, 100).detach()); 212cb93a386Sopenharmony_ci fPaths.push_back(b.cubicTo(0, 0, 0, 0, 100, 100).detach()); 213cb93a386Sopenharmony_ci 214cb93a386Sopenharmony_ci // skbug.com/8928 215cb93a386Sopenharmony_ci fPaths.push_back(b.moveTo(16.875f, 192.594f) 216cb93a386Sopenharmony_ci .cubicTo(45.625f, 192.594f, 74.375f, 192.594f, 103.125f, 192.594f) 217cb93a386Sopenharmony_ci .cubicTo(88.75f, 167.708f, 74.375f, 142.823f, 60, 117.938f) 218cb93a386Sopenharmony_ci .cubicTo(45.625f, 142.823f, 31.25f, 167.708f, 16.875f, 192.594f) 219cb93a386Sopenharmony_ci .close() 220cb93a386Sopenharmony_ci .detach()); 221cb93a386Sopenharmony_ci SkMatrix m; 222cb93a386Sopenharmony_ci m.setAll(0.1f, 0, -1, 0, 0.115207f, -2.64977f, 0, 0, 1); 223cb93a386Sopenharmony_ci fPaths.back().transform(m); 224cb93a386Sopenharmony_ci 225cb93a386Sopenharmony_ci // small circle. This is listed last so that it has device coords far 226cb93a386Sopenharmony_ci // from the origin (small area relative to x,y values). 227cb93a386Sopenharmony_ci fPaths.push_back(SkPath::Circle(0, 0, 1.2f)); 228cb93a386Sopenharmony_ci } 229cb93a386Sopenharmony_ci 230cb93a386Sopenharmony_ci void onDraw(SkCanvas* canvas) override { 231cb93a386Sopenharmony_ci this->makePaths(); 232cb93a386Sopenharmony_ci 233cb93a386Sopenharmony_ci SkPaint paint; 234cb93a386Sopenharmony_ci paint.setAntiAlias(true); 235cb93a386Sopenharmony_ci SkRandom rand; 236cb93a386Sopenharmony_ci canvas->translate(20, 20); 237cb93a386Sopenharmony_ci 238cb93a386Sopenharmony_ci // As we've added more paths this has gotten pretty big. Scale the whole thing down. 239cb93a386Sopenharmony_ci canvas->scale(2.0f/3, 2.0f/3); 240cb93a386Sopenharmony_ci 241cb93a386Sopenharmony_ci for (int i = 0; i < fPaths.count(); ++i) { 242cb93a386Sopenharmony_ci canvas->save(); 243cb93a386Sopenharmony_ci // position the path, and make it at off-integer coords. 244cb93a386Sopenharmony_ci canvas->translate(200.0f * (i % 5) + 1.0f/10, 245cb93a386Sopenharmony_ci 200.0f * (i / 5) + 9.0f/10); 246cb93a386Sopenharmony_ci SkColor color = rand.nextU(); 247cb93a386Sopenharmony_ci color |= 0xff000000; 248cb93a386Sopenharmony_ci paint.setColor(color); 249cb93a386Sopenharmony_ci#if 0 // This hitting on 32bit Linux builds for some paths. Temporarily disabling while it is 250cb93a386Sopenharmony_ci // debugged. 251cb93a386Sopenharmony_ci SkASSERT(fPaths[i].isConvex()); 252cb93a386Sopenharmony_ci#endif 253cb93a386Sopenharmony_ci canvas->drawPath(fPaths[i], paint); 254cb93a386Sopenharmony_ci canvas->restore(); 255cb93a386Sopenharmony_ci } 256cb93a386Sopenharmony_ci } 257cb93a386Sopenharmony_ci 258cb93a386Sopenharmony_ci SkTArray<SkPath> fPaths; 259cb93a386Sopenharmony_ci}; 260cb93a386Sopenharmony_ci} // namespace 261cb93a386Sopenharmony_ci 262cb93a386Sopenharmony_ciDEF_GM( return new ConvexPathsGM; ) 263