Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / bench / PathBench.cpp
1
2 /*
3  * Copyright 2011 Google Inc.
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 #include "Benchmark.h"
9 #include "SkBitmap.h"
10 #include "SkCanvas.h"
11 #include "SkColorPriv.h"
12 #include "SkPaint.h"
13 #include "SkRandom.h"
14 #include "SkShader.h"
15 #include "SkString.h"
16 #include "SkTArray.h"
17
18 enum Flags {
19     kStroke_Flag = 1 << 0,
20     kBig_Flag    = 1 << 1
21 };
22
23 #define FLAGS00  Flags(0)
24 #define FLAGS01  Flags(kStroke_Flag)
25 #define FLAGS10  Flags(kBig_Flag)
26 #define FLAGS11  Flags(kStroke_Flag | kBig_Flag)
27
28 class PathBench : public Benchmark {
29     SkPaint     fPaint;
30     SkString    fName;
31     Flags       fFlags;
32 public:
33     PathBench(Flags flags) : fFlags(flags) {
34         fPaint.setStyle(flags & kStroke_Flag ? SkPaint::kStroke_Style :
35                         SkPaint::kFill_Style);
36         fPaint.setStrokeWidth(SkIntToScalar(5));
37         fPaint.setStrokeJoin(SkPaint::kBevel_Join);
38     }
39
40     virtual void appendName(SkString*) = 0;
41     virtual void makePath(SkPath*) = 0;
42     virtual int complexity() { return 0; }
43
44 protected:
45     virtual const char* onGetName() SK_OVERRIDE {
46         fName.printf("path_%s_%s_",
47                      fFlags & kStroke_Flag ? "stroke" : "fill",
48                      fFlags & kBig_Flag ? "big" : "small");
49         this->appendName(&fName);
50         return fName.c_str();
51     }
52
53     virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE {
54         SkPaint paint(fPaint);
55         this->setupPaint(&paint);
56
57         SkPath path;
58         this->makePath(&path);
59         if (fFlags & kBig_Flag) {
60             SkMatrix m;
61             m.setScale(SkIntToScalar(10), SkIntToScalar(10));
62             path.transform(m);
63         }
64
65         int count = loops;
66         if (fFlags & kBig_Flag) {
67             count >>= 2;
68         }
69         count >>= (3 * complexity());
70
71         for (int i = 0; i < count; i++) {
72             canvas->drawPath(path, paint);
73         }
74     }
75
76 private:
77     typedef Benchmark INHERITED;
78 };
79
80 class TrianglePathBench : public PathBench {
81 public:
82     TrianglePathBench(Flags flags) : INHERITED(flags) {}
83
84     virtual void appendName(SkString* name) SK_OVERRIDE {
85         name->append("triangle");
86     }
87     virtual void makePath(SkPath* path) SK_OVERRIDE {
88         static const int gCoord[] = {
89             10, 10, 15, 5, 20, 20
90         };
91         path->moveTo(SkIntToScalar(gCoord[0]), SkIntToScalar(gCoord[1]));
92         path->lineTo(SkIntToScalar(gCoord[2]), SkIntToScalar(gCoord[3]));
93         path->lineTo(SkIntToScalar(gCoord[4]), SkIntToScalar(gCoord[5]));
94         path->close();
95     }
96 private:
97     typedef PathBench INHERITED;
98 };
99
100 class RectPathBench : public PathBench {
101 public:
102     RectPathBench(Flags flags) : INHERITED(flags) {}
103
104     virtual void appendName(SkString* name) SK_OVERRIDE {
105         name->append("rect");
106     }
107     virtual void makePath(SkPath* path) SK_OVERRIDE {
108         SkRect r = { 10, 10, 20, 20 };
109         path->addRect(r);
110     }
111 private:
112     typedef PathBench INHERITED;
113 };
114
115 class OvalPathBench : public PathBench {
116 public:
117     OvalPathBench(Flags flags) : INHERITED(flags) {}
118
119     virtual void appendName(SkString* name) SK_OVERRIDE {
120         name->append("oval");
121     }
122     virtual void makePath(SkPath* path) SK_OVERRIDE {
123         SkRect r = { 10, 10, 23, 20 };
124         path->addOval(r);
125     }
126 private:
127     typedef PathBench INHERITED;
128 };
129
130 class CirclePathBench: public PathBench {
131 public:
132     CirclePathBench(Flags flags) : INHERITED(flags) {}
133
134     virtual void appendName(SkString* name) SK_OVERRIDE {
135         name->append("circle");
136     }
137     virtual void makePath(SkPath* path) SK_OVERRIDE {
138         path->addCircle(SkIntToScalar(20), SkIntToScalar(20),
139                         SkIntToScalar(10));
140     }
141 private:
142     typedef PathBench INHERITED;
143 };
144
145 class SawToothPathBench : public PathBench {
146 public:
147     SawToothPathBench(Flags flags) : INHERITED(flags) {}
148
149     virtual void appendName(SkString* name) SK_OVERRIDE {
150         name->append("sawtooth");
151     }
152     virtual void makePath(SkPath* path) {
153         SkScalar x = SkIntToScalar(20);
154         SkScalar y = SkIntToScalar(20);
155         const SkScalar x0 = x;
156         const SkScalar dx = SK_Scalar1 * 5;
157         const SkScalar dy = SK_Scalar1 * 10;
158
159         path->moveTo(x, y);
160         for (int i = 0; i < 32; i++) {
161             x += dx;
162             path->lineTo(x, y - dy);
163             x += dx;
164             path->lineTo(x, y + dy);
165         }
166         path->lineTo(x, y + 2 * dy);
167         path->lineTo(x0, y + 2 * dy);
168         path->close();
169     }
170     virtual int complexity() SK_OVERRIDE { return 1; }
171 private:
172     typedef PathBench INHERITED;
173 };
174
175 class LongCurvedPathBench : public PathBench {
176 public:
177     LongCurvedPathBench(Flags flags) : INHERITED(flags) {}
178
179     virtual void appendName(SkString* name) SK_OVERRIDE {
180         name->append("long_curved");
181     }
182     virtual void makePath(SkPath* path) SK_OVERRIDE {
183         SkRandom rand (12);
184         int i;
185         for (i = 0; i < 100; i++) {
186             path->quadTo(SkScalarMul(rand.nextUScalar1(), SkIntToScalar(640)),
187                          SkScalarMul(rand.nextUScalar1(), SkIntToScalar(480)),
188                          SkScalarMul(rand.nextUScalar1(), SkIntToScalar(640)),
189                          SkScalarMul(rand.nextUScalar1(), SkIntToScalar(480)));
190         }
191         path->close();
192     }
193     virtual int complexity() SK_OVERRIDE { return 2; }
194 private:
195     typedef PathBench INHERITED;
196 };
197
198 class LongLinePathBench : public PathBench {
199 public:
200     LongLinePathBench(Flags flags) : INHERITED(flags) {}
201
202     virtual void appendName(SkString* name) SK_OVERRIDE {
203         name->append("long_line");
204     }
205     virtual void makePath(SkPath* path) SK_OVERRIDE {
206         SkRandom rand;
207         path->moveTo(rand.nextUScalar1() * 640, rand.nextUScalar1() * 480);
208         for (size_t i = 1; i < 100; i++) {
209             path->lineTo(rand.nextUScalar1() * 640, rand.nextUScalar1() * 480);
210         }
211     }
212     virtual int complexity() SK_OVERRIDE { return 2; }
213 private:
214     typedef PathBench INHERITED;
215 };
216
217 class RandomPathBench : public Benchmark {
218 public:
219     virtual bool isSuitableFor(Backend backend) SK_OVERRIDE {
220         return backend == kNonRendering_Backend;
221     }
222
223 protected:
224     void createData(int minVerbs,
225                     int maxVerbs,
226                     bool allowMoves = true,
227                     SkRect* bounds = NULL) {
228         SkRect tempBounds;
229         if (NULL == bounds) {
230             tempBounds.setXYWH(0, 0, SK_Scalar1, SK_Scalar1);
231             bounds = &tempBounds;
232         }
233         fVerbCnts.reset(kNumVerbCnts);
234         for (int i = 0; i < kNumVerbCnts; ++i) {
235             fVerbCnts[i] = fRandom.nextRangeU(minVerbs, maxVerbs + 1);
236         }
237         fVerbs.reset(kNumVerbs);
238         for (int i = 0; i < kNumVerbs; ++i) {
239             do {
240                 fVerbs[i] = static_cast<SkPath::Verb>(fRandom.nextULessThan(SkPath::kDone_Verb));
241             } while (!allowMoves && SkPath::kMove_Verb == fVerbs[i]);
242         }
243         fPoints.reset(kNumPoints);
244         for (int i = 0; i < kNumPoints; ++i) {
245             fPoints[i].set(fRandom.nextRangeScalar(bounds->fLeft, bounds->fRight),
246                            fRandom.nextRangeScalar(bounds->fTop, bounds->fBottom));
247         }
248         this->restartMakingPaths();
249     }
250
251     void restartMakingPaths() {
252         fCurrPath = 0;
253         fCurrVerb = 0;
254         fCurrPoint = 0;
255     }
256
257     void makePath(SkPath* path) {
258         int vCount = fVerbCnts[(fCurrPath++) & (kNumVerbCnts - 1)];
259         for (int v = 0; v < vCount; ++v) {
260             int verb = fVerbs[(fCurrVerb++) & (kNumVerbs - 1)];
261             switch (verb) {
262                 case SkPath::kMove_Verb:
263                     path->moveTo(fPoints[(fCurrPoint++) & (kNumPoints - 1)]);
264                     break;
265                 case SkPath::kLine_Verb:
266                     path->lineTo(fPoints[(fCurrPoint++) & (kNumPoints - 1)]);
267                     break;
268                 case SkPath::kQuad_Verb:
269                     path->quadTo(fPoints[(fCurrPoint + 0) & (kNumPoints - 1)],
270                                  fPoints[(fCurrPoint + 1) & (kNumPoints - 1)]);
271                     fCurrPoint += 2;
272                     break;
273                 case SkPath::kConic_Verb:
274                     path->conicTo(fPoints[(fCurrPoint + 0) & (kNumPoints - 1)],
275                                   fPoints[(fCurrPoint + 1) & (kNumPoints - 1)],
276                                   SK_ScalarHalf);
277                     fCurrPoint += 2;
278                     break;
279                 case SkPath::kCubic_Verb:
280                     path->cubicTo(fPoints[(fCurrPoint + 0) & (kNumPoints - 1)],
281                                   fPoints[(fCurrPoint + 1) & (kNumPoints - 1)],
282                                   fPoints[(fCurrPoint + 2) & (kNumPoints - 1)]);
283                     fCurrPoint += 3;
284                     break;
285                 case SkPath::kClose_Verb:
286                     path->close();
287                     break;
288                 default:
289                     SkDEBUGFAIL("Unexpected path verb");
290                     break;
291             }
292         }
293     }
294
295     void finishedMakingPaths() {
296         fVerbCnts.reset(0);
297         fVerbs.reset(0);
298         fPoints.reset(0);
299     }
300
301 private:
302     enum {
303         // these should all be pow 2
304         kNumVerbCnts = 1 << 5,
305         kNumVerbs    = 1 << 5,
306         kNumPoints   = 1 << 5,
307     };
308     SkAutoTArray<int>           fVerbCnts;
309     SkAutoTArray<SkPath::Verb>  fVerbs;
310     SkAutoTArray<SkPoint>       fPoints;
311     int                         fCurrPath;
312     int                         fCurrVerb;
313     int                         fCurrPoint;
314     SkRandom                    fRandom;
315     typedef Benchmark INHERITED;
316 };
317
318 class PathCreateBench : public RandomPathBench {
319 public:
320     PathCreateBench()  {
321     }
322
323 protected:
324     virtual const char* onGetName() SK_OVERRIDE {
325         return "path_create";
326     }
327
328     virtual void onPreDraw() SK_OVERRIDE {
329         this->createData(10, 100);
330     }
331
332     virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE {
333         for (int i = 0; i < loops; ++i) {
334             if (i % 1000 == 0) {
335                 fPath.reset();  // PathRef memory can grow without bound otherwise.
336             }
337             this->makePath(&fPath);
338         }
339         this->restartMakingPaths();
340     }
341
342 private:
343     SkPath fPath;
344
345     typedef RandomPathBench INHERITED;
346 };
347
348 class PathCopyBench : public RandomPathBench {
349 public:
350     PathCopyBench()  {
351     }
352
353 protected:
354     virtual const char* onGetName() SK_OVERRIDE {
355         return "path_copy";
356     }
357     virtual void onPreDraw() SK_OVERRIDE {
358         this->createData(10, 100);
359         fPaths.reset(kPathCnt);
360         fCopies.reset(kPathCnt);
361         for (int i = 0; i < kPathCnt; ++i) {
362             this->makePath(&fPaths[i]);
363         }
364         this->finishedMakingPaths();
365     }
366     virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE {
367         for (int i = 0; i < loops; ++i) {
368             int idx = i & (kPathCnt - 1);
369             fCopies[idx] = fPaths[idx];
370         }
371     }
372
373 private:
374     enum {
375         // must be a pow 2
376         kPathCnt = 1 << 5,
377     };
378     SkAutoTArray<SkPath> fPaths;
379     SkAutoTArray<SkPath> fCopies;
380
381     typedef RandomPathBench INHERITED;
382 };
383
384 class PathTransformBench : public RandomPathBench {
385 public:
386     PathTransformBench(bool inPlace) : fInPlace(inPlace) {}
387
388 protected:
389     virtual const char* onGetName() SK_OVERRIDE {
390         return fInPlace ? "path_transform_in_place" : "path_transform_copy";
391     }
392
393     virtual void onPreDraw() SK_OVERRIDE {
394         fMatrix.setScale(5 * SK_Scalar1, 6 * SK_Scalar1);
395         this->createData(10, 100);
396         fPaths.reset(kPathCnt);
397         for (int i = 0; i < kPathCnt; ++i) {
398             this->makePath(&fPaths[i]);
399         }
400         this->finishedMakingPaths();
401         if (!fInPlace) {
402             fTransformed.reset(kPathCnt);
403         }
404     }
405
406     virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE {
407         if (fInPlace) {
408             for (int i = 0; i < loops; ++i) {
409                 fPaths[i & (kPathCnt - 1)].transform(fMatrix);
410             }
411         } else {
412             for (int i = 0; i < loops; ++i) {
413                 int idx = i & (kPathCnt - 1);
414                 fPaths[idx].transform(fMatrix, &fTransformed[idx]);
415             }
416         }
417     }
418
419 private:
420     enum {
421         // must be a pow 2
422         kPathCnt = 1 << 5,
423     };
424     SkAutoTArray<SkPath> fPaths;
425     SkAutoTArray<SkPath> fTransformed;
426
427     SkMatrix fMatrix;
428     bool fInPlace;
429     typedef RandomPathBench INHERITED;
430 };
431
432 class PathEqualityBench : public RandomPathBench {
433 public:
434     PathEqualityBench() { }
435
436 protected:
437     virtual const char* onGetName() SK_OVERRIDE {
438         return "path_equality_50%";
439     }
440
441     virtual void onPreDraw() SK_OVERRIDE {
442         fParity = 0;
443         this->createData(10, 100);
444         fPaths.reset(kPathCnt);
445         fCopies.reset(kPathCnt);
446         for (int i = 0; i < kPathCnt; ++i) {
447             this->makePath(&fPaths[i]);
448             fCopies[i] = fPaths[i];
449         }
450         this->finishedMakingPaths();
451     }
452
453     virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE {
454         for (int i = 0; i < loops; ++i) {
455             int idx = i & (kPathCnt - 1);
456             fParity ^= (fPaths[idx] == fCopies[idx & ~0x1]);
457         }
458     }
459
460 private:
461     bool fParity; // attempt to keep compiler from optimizing out the ==
462     enum {
463         // must be a pow 2
464         kPathCnt = 1 << 5,
465     };
466     SkAutoTArray<SkPath> fPaths;
467     SkAutoTArray<SkPath> fCopies;
468     typedef RandomPathBench INHERITED;
469 };
470
471 class SkBench_AddPathTest : public RandomPathBench {
472 public:
473     enum AddType {
474         kAdd_AddType,
475         kAddTrans_AddType,
476         kAddMatrix_AddType,
477         kReverseAdd_AddType,
478         kReversePathTo_AddType,
479     };
480
481     SkBench_AddPathTest(AddType type) : fType(type) {
482         fMatrix.setRotate(60 * SK_Scalar1);
483     }
484
485 protected:
486     virtual const char* onGetName() SK_OVERRIDE {
487         switch (fType) {
488             case kAdd_AddType:
489                 return "path_add_path";
490             case kAddTrans_AddType:
491                 return "path_add_path_trans";
492             case kAddMatrix_AddType:
493                 return "path_add_path_matrix";
494             case kReverseAdd_AddType:
495                 return "path_reverse_add_path";
496             case kReversePathTo_AddType:
497                 return "path_reverse_path_to";
498             default:
499                 SkDEBUGFAIL("Bad add type");
500                 return "";
501         }
502     }
503
504     virtual void onPreDraw() SK_OVERRIDE {
505         // reversePathTo assumes a single contour path.
506         bool allowMoves = kReversePathTo_AddType != fType;
507         this->createData(10, 100, allowMoves);
508         fPaths0.reset(kPathCnt);
509         fPaths1.reset(kPathCnt);
510         for (int i = 0; i < kPathCnt; ++i) {
511             this->makePath(&fPaths0[i]);
512             this->makePath(&fPaths1[i]);
513         }
514         this->finishedMakingPaths();
515     }
516
517     virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE {
518         switch (fType) {
519             case kAdd_AddType:
520                 for (int i = 0; i < loops; ++i) {
521                     int idx = i & (kPathCnt - 1);
522                     SkPath result = fPaths0[idx];
523                     result.addPath(fPaths1[idx]);
524                 }
525                 break;
526             case kAddTrans_AddType:
527                 for (int i = 0; i < loops; ++i) {
528                     int idx = i & (kPathCnt - 1);
529                     SkPath result = fPaths0[idx];
530                     result.addPath(fPaths1[idx], 2 * SK_Scalar1, 5 * SK_Scalar1);
531                 }
532                 break;
533             case kAddMatrix_AddType:
534                 for (int i = 0; i < loops; ++i) {
535                     int idx = i & (kPathCnt - 1);
536                     SkPath result = fPaths0[idx];
537                     result.addPath(fPaths1[idx], fMatrix);
538                 }
539                 break;
540             case kReverseAdd_AddType:
541                 for (int i = 0; i < loops; ++i) {
542                     int idx = i & (kPathCnt - 1);
543                     SkPath result = fPaths0[idx];
544                     result.reverseAddPath(fPaths1[idx]);
545                 }
546                 break;
547             case kReversePathTo_AddType:
548                 for (int i = 0; i < loops; ++i) {
549                     int idx = i & (kPathCnt - 1);
550                     SkPath result = fPaths0[idx];
551                     result.reversePathTo(fPaths1[idx]);
552                 }
553                 break;
554         }
555     }
556
557 private:
558     AddType fType; // or reverseAddPath
559     enum {
560         // must be a pow 2
561         kPathCnt = 1 << 5,
562     };
563     SkAutoTArray<SkPath> fPaths0;
564     SkAutoTArray<SkPath> fPaths1;
565     SkMatrix         fMatrix;
566     typedef RandomPathBench INHERITED;
567 };
568
569
570 class CirclesBench : public Benchmark {
571 protected:
572     SkString            fName;
573     Flags               fFlags;
574
575 public:
576     CirclesBench(Flags flags) : fFlags(flags) {
577         fName.printf("circles_%s", fFlags & kStroke_Flag ? "stroke" : "fill");
578     }
579
580 protected:
581     virtual const char* onGetName() SK_OVERRIDE {
582         return fName.c_str();
583     }
584
585     virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE {
586         SkPaint paint;
587
588         paint.setColor(SK_ColorBLACK);
589         paint.setAntiAlias(true);
590         if (fFlags & kStroke_Flag) {
591             paint.setStyle(SkPaint::kStroke_Style);
592         }
593
594         SkRandom rand;
595
596         SkRect r;
597
598         for (int i = 0; i < loops; ++i) {
599             SkScalar radius = rand.nextUScalar1() * 3;
600             r.fLeft = rand.nextUScalar1() * 300;
601             r.fTop =  rand.nextUScalar1() * 300;
602             r.fRight =  r.fLeft + 2 * radius;
603             r.fBottom = r.fTop + 2 * radius;
604
605             if (fFlags & kStroke_Flag) {
606                 paint.setStrokeWidth(rand.nextUScalar1() * 5.0f);
607             }
608
609             SkPath temp;
610
611             // mimic how Chrome does circles
612             temp.arcTo(r, 0, 0, false);
613             temp.addOval(r, SkPath::kCCW_Direction);
614             temp.arcTo(r, 360, 0, true);
615             temp.close();
616
617             canvas->drawPath(temp, paint);
618         }
619     }
620
621 private:
622     typedef Benchmark INHERITED;
623 };
624
625
626 // Chrome creates its own round rects with each corner possibly being different.
627 // In its "zero radius" incarnation it creates degenerate round rects.
628 // Note: PathTest::test_arb_round_rect_is_convex and
629 // test_arb_zero_rad_round_rect_is_rect perform almost exactly
630 // the same test (but with no drawing)
631 class ArbRoundRectBench : public Benchmark {
632 protected:
633     SkString            fName;
634
635 public:
636     ArbRoundRectBench(bool zeroRad) : fZeroRad(zeroRad) {
637         if (zeroRad) {
638             fName.printf("zeroradroundrect");
639         } else {
640             fName.printf("arbroundrect");
641         }
642     }
643
644 protected:
645     virtual const char* onGetName() SK_OVERRIDE {
646         return fName.c_str();
647     }
648
649     static void add_corner_arc(SkPath* path, const SkRect& rect,
650                                SkScalar xIn, SkScalar yIn,
651                                int startAngle)
652     {
653
654         SkScalar rx = SkMinScalar(rect.width(), xIn);
655         SkScalar ry = SkMinScalar(rect.height(), yIn);
656
657         SkRect arcRect;
658         arcRect.set(-rx, -ry, rx, ry);
659         switch (startAngle) {
660         case 0:
661             arcRect.offset(rect.fRight - arcRect.fRight, rect.fBottom - arcRect.fBottom);
662             break;
663         case 90:
664             arcRect.offset(rect.fLeft - arcRect.fLeft, rect.fBottom - arcRect.fBottom);
665             break;
666         case 180:
667             arcRect.offset(rect.fLeft - arcRect.fLeft, rect.fTop - arcRect.fTop);
668             break;
669         case 270:
670             arcRect.offset(rect.fRight - arcRect.fRight, rect.fTop - arcRect.fTop);
671             break;
672         default:
673             break;
674         }
675
676         path->arcTo(arcRect, SkIntToScalar(startAngle), SkIntToScalar(90), false);
677     }
678
679     static void make_arb_round_rect(SkPath* path, const SkRect& r,
680                                     SkScalar xCorner, SkScalar yCorner) {
681         // we are lazy here and use the same x & y for each corner
682         add_corner_arc(path, r, xCorner, yCorner, 270);
683         add_corner_arc(path, r, xCorner, yCorner, 0);
684         add_corner_arc(path, r, xCorner, yCorner, 90);
685         add_corner_arc(path, r, xCorner, yCorner, 180);
686         path->close();
687
688         SkASSERT(path->isConvex());
689     }
690
691     virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE {
692         SkRandom rand;
693         SkRect r;
694
695         for (int i = 0; i < loops; ++i) {
696             SkPaint paint;
697             paint.setColor(0xff000000 | rand.nextU());
698             paint.setAntiAlias(true);
699
700             SkScalar size = rand.nextUScalar1() * 30;
701             if (size < SK_Scalar1) {
702                 continue;
703             }
704             r.fLeft = rand.nextUScalar1() * 300;
705             r.fTop =  rand.nextUScalar1() * 300;
706             r.fRight =  r.fLeft + 2 * size;
707             r.fBottom = r.fTop + 2 * size;
708
709             SkPath temp;
710
711             if (fZeroRad) {
712                 make_arb_round_rect(&temp, r, 0, 0);
713
714                 SkASSERT(temp.isRect(NULL));
715             } else {
716                 make_arb_round_rect(&temp, r, r.width() / 10, r.height() / 15);
717             }
718
719             canvas->drawPath(temp, paint);
720         }
721     }
722
723 private:
724     bool fZeroRad;      // should 0 radius rounds rects be tested?
725
726     typedef Benchmark INHERITED;
727 };
728
729 class ConservativelyContainsBench : public Benchmark {
730 public:
731     enum Type {
732         kRect_Type,
733         kRoundRect_Type,
734         kOval_Type,
735     };
736
737     ConservativelyContainsBench(Type type)  {
738         fParity = false;
739         fName = "conservatively_contains_";
740         switch (type) {
741             case kRect_Type:
742                 fName.append("rect");
743                 fPath.addRect(kBaseRect);
744                 break;
745             case kRoundRect_Type:
746                 fName.append("round_rect");
747                 fPath.addRoundRect(kBaseRect, kRRRadii[0], kRRRadii[1]);
748                 break;
749             case kOval_Type:
750                 fName.append("oval");
751                 fPath.addOval(kBaseRect);
752                 break;
753         }
754     }
755
756     virtual bool isSuitableFor(Backend backend) SK_OVERRIDE {
757         return backend == kNonRendering_Backend;
758     }
759
760 private:
761     virtual const char* onGetName() SK_OVERRIDE {
762         return fName.c_str();
763     }
764
765     virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE {
766         for (int i = 0; i < loops; ++i) {
767             const SkRect& rect = fQueryRects[i % kQueryRectCnt];
768             fParity = fParity != fPath.conservativelyContainsRect(rect);
769         }
770     }
771
772     virtual void onPreDraw() SK_OVERRIDE {
773         fQueryRects.setCount(kQueryRectCnt);
774
775         SkRandom rand;
776         for (int i = 0; i < kQueryRectCnt; ++i) {
777             SkSize size;
778             SkPoint xy;
779             size.fWidth = rand.nextRangeScalar(kQueryMin.fWidth,  kQueryMax.fWidth);
780             size.fHeight = rand.nextRangeScalar(kQueryMin.fHeight, kQueryMax.fHeight);
781             xy.fX = rand.nextRangeScalar(kBounds.fLeft, kBounds.fRight - size.fWidth);
782             xy.fY = rand.nextRangeScalar(kBounds.fTop, kBounds.fBottom - size.fHeight);
783
784             fQueryRects[i] = SkRect::MakeXYWH(xy.fX, xy.fY, size.fWidth, size.fHeight);
785         }
786     }
787
788     enum {
789         kQueryRectCnt = 400,
790     };
791     static const SkRect kBounds;   // bounds for all random query rects
792     static const SkSize kQueryMin; // minimum query rect size, should be <= kQueryMax
793     static const SkSize kQueryMax; // max query rect size, should < kBounds
794     static const SkRect kBaseRect; // rect that is used to construct the path
795     static const SkScalar kRRRadii[2]; // x and y radii for round rect
796
797     SkString            fName;
798     SkPath              fPath;
799     bool                fParity;
800     SkTDArray<SkRect>   fQueryRects;
801
802     typedef Benchmark INHERITED;
803 };
804
805 ///////////////////////////////////////////////////////////////////////////////
806
807 #include "SkGeometry.h"
808
809 class ConicBench_Chop5 : public Benchmark {
810     SkConic fRQ;
811 public:
812     ConicBench_Chop5()  {
813         fRQ.fPts[0].set(0, 0);
814         fRQ.fPts[1].set(100, 0);
815         fRQ.fPts[2].set(100, 100);
816         fRQ.fW = SkScalarCos(SK_ScalarPI/4);
817     }
818
819 private:
820     virtual const char* onGetName() SK_OVERRIDE {
821         return "ratquad-chop-0.5";
822     }
823
824     virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE {
825         SkConic dst[2];
826         for (int i = 0; i < loops; ++i) {
827             fRQ.chopAt(0.5f, dst);
828         }
829     }
830
831     typedef Benchmark INHERITED;
832 };
833
834 class ConicBench_ChopHalf : public Benchmark {
835     SkConic fRQ;
836 public:
837     ConicBench_ChopHalf()  {
838         fRQ.fPts[0].set(0, 0);
839         fRQ.fPts[1].set(100, 0);
840         fRQ.fPts[2].set(100, 100);
841         fRQ.fW = SkScalarCos(SK_ScalarPI/4);
842     }
843
844 private:
845     virtual const char* onGetName() SK_OVERRIDE {
846         return "ratquad-chop-half";
847     }
848
849     virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE {
850         SkConic dst[2];
851         for (int i = 0; i < loops; ++i) {
852             fRQ.chop(dst);
853         }
854     }
855
856     typedef Benchmark INHERITED;
857 };
858
859 ///////////////////////////////////////////////////////////////////////////////
860
861 static void rand_conic(SkConic* conic, SkRandom& rand) {
862     for (int i = 0; i < 3; ++i) {
863         conic->fPts[i].set(rand.nextUScalar1() * 100, rand.nextUScalar1() * 100);
864     }
865     if (rand.nextUScalar1() > 0.5f) {
866         conic->fW = rand.nextUScalar1();
867     } else {
868         conic->fW = 1 + rand.nextUScalar1() * 4;
869     }
870 }
871
872 class ConicBench : public Benchmark {
873 public:
874     ConicBench()  {
875         SkRandom rand;
876         for (int i = 0; i < CONICS; ++i) {
877             rand_conic(&fConics[i], rand);
878         }
879     }
880
881     virtual bool isSuitableFor(Backend backend) SK_OVERRIDE {
882         return backend == kNonRendering_Backend;
883     }
884
885 protected:
886     enum {
887         CONICS = 100
888     };
889     SkConic fConics[CONICS];
890
891 private:
892     typedef Benchmark INHERITED;
893 };
894
895 class ConicBench_ComputeError : public ConicBench {
896 public:
897     ConicBench_ComputeError()  {}
898
899 protected:
900     virtual const char* onGetName() SK_OVERRIDE {
901         return "conic-compute-error";
902     }
903
904     virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE {
905         SkVector err;
906         for (int i = 0; i < loops; ++i) {
907             for (int j = 0; j < CONICS; ++j) {
908                 fConics[j].computeAsQuadError(&err);
909             }
910         }
911     }
912
913 private:
914     typedef ConicBench INHERITED;
915 };
916
917 class ConicBench_asQuadTol : public ConicBench {
918 public:
919     ConicBench_asQuadTol()  {}
920
921 protected:
922     virtual const char* onGetName() SK_OVERRIDE {
923         return "conic-asQuadTol";
924     }
925
926     virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE {
927         for (int i = 0; i < loops; ++i) {
928             for (int j = 0; j < CONICS; ++j) {
929                 fConics[j].asQuadTol(SK_ScalarHalf);
930             }
931         }
932     }
933
934 private:
935     typedef ConicBench INHERITED;
936 };
937
938 class ConicBench_quadPow2 : public ConicBench {
939 public:
940     ConicBench_quadPow2()  {}
941
942 protected:
943     virtual const char* onGetName() SK_OVERRIDE {
944         return "conic-quadPow2";
945     }
946
947     virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE {
948         for (int i = 0; i < loops; ++i) {
949             for (int j = 0; j < CONICS; ++j) {
950                 fConics[j].computeQuadPOW2(SK_ScalarHalf);
951             }
952         }
953     }
954
955 private:
956     typedef ConicBench INHERITED;
957 };
958
959 ///////////////////////////////////////////////////////////////////////////////
960
961 const SkRect ConservativelyContainsBench::kBounds = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
962 const SkSize ConservativelyContainsBench::kQueryMin = SkSize::Make(SkIntToScalar(1), SkIntToScalar(1));
963 const SkSize ConservativelyContainsBench::kQueryMax = SkSize::Make(SkIntToScalar(40), SkIntToScalar(40));
964 const SkRect ConservativelyContainsBench::kBaseRect = SkRect::MakeXYWH(SkIntToScalar(25), SkIntToScalar(25), SkIntToScalar(50), SkIntToScalar(50));
965 const SkScalar ConservativelyContainsBench::kRRRadii[2] = {SkIntToScalar(5), SkIntToScalar(10)};
966
967 DEF_BENCH( return new TrianglePathBench(FLAGS00); )
968 DEF_BENCH( return new TrianglePathBench(FLAGS01); )
969 DEF_BENCH( return new TrianglePathBench(FLAGS10); )
970 DEF_BENCH( return new TrianglePathBench(FLAGS11); )
971
972 DEF_BENCH( return new RectPathBench(FLAGS00); )
973 DEF_BENCH( return new RectPathBench(FLAGS01); )
974 DEF_BENCH( return new RectPathBench(FLAGS10); )
975 DEF_BENCH( return new RectPathBench(FLAGS11); )
976
977 DEF_BENCH( return new OvalPathBench(FLAGS00); )
978 DEF_BENCH( return new OvalPathBench(FLAGS01); )
979 DEF_BENCH( return new OvalPathBench(FLAGS10); )
980 DEF_BENCH( return new OvalPathBench(FLAGS11); )
981
982 DEF_BENCH( return new CirclePathBench(FLAGS00); )
983 DEF_BENCH( return new CirclePathBench(FLAGS01); )
984 DEF_BENCH( return new CirclePathBench(FLAGS10); )
985 DEF_BENCH( return new CirclePathBench(FLAGS11); )
986
987 DEF_BENCH( return new SawToothPathBench(FLAGS00); )
988 DEF_BENCH( return new SawToothPathBench(FLAGS01); )
989
990 DEF_BENCH( return new LongCurvedPathBench(FLAGS00); )
991 DEF_BENCH( return new LongCurvedPathBench(FLAGS01); )
992 DEF_BENCH( return new LongLinePathBench(FLAGS00); )
993 DEF_BENCH( return new LongLinePathBench(FLAGS01); )
994
995 DEF_BENCH( return new PathCreateBench(); )
996 DEF_BENCH( return new PathCopyBench(); )
997 DEF_BENCH( return new PathTransformBench(true); )
998 DEF_BENCH( return new PathTransformBench(false); )
999 DEF_BENCH( return new PathEqualityBench(); )
1000
1001 DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kAdd_AddType); )
1002 DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kAddTrans_AddType); )
1003 DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kAddMatrix_AddType); )
1004 DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kReverseAdd_AddType); )
1005 DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kReversePathTo_AddType); )
1006
1007 DEF_BENCH( return new CirclesBench(FLAGS00); )
1008 DEF_BENCH( return new CirclesBench(FLAGS01); )
1009 DEF_BENCH( return new ArbRoundRectBench(false); )
1010 DEF_BENCH( return new ArbRoundRectBench(true); )
1011 DEF_BENCH( return new ConservativelyContainsBench(ConservativelyContainsBench::kRect_Type); )
1012 DEF_BENCH( return new ConservativelyContainsBench(ConservativelyContainsBench::kRoundRect_Type); )
1013 DEF_BENCH( return new ConservativelyContainsBench(ConservativelyContainsBench::kOval_Type); )
1014
1015 // These seem to be optimized away, which is troublesome for timing.
1016 /*
1017 DEF_BENCH( return new ConicBench_Chop5() )
1018 DEF_BENCH( return new ConicBench_ChopHalf() )
1019 DEF_BENCH( return new ConicBench_ComputeError() )
1020 DEF_BENCH( return new ConicBench_asQuadTol() )
1021 DEF_BENCH( return new ConicBench_quadPow2() )
1022 */