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