1/*
2 * Copyright 2012 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
8#include "gm.h"
9#include "SkCanvas.h"
10#include "SkRRect.h"
11#include "SkPath.h"
12
13typedef void (*InsetProc)(const SkRRect&, SkScalar dx, SkScalar dy, SkRRect*);
14
15static void inset0(const SkRRect& src, SkScalar dx, SkScalar dy, SkRRect* dst) {
16    SkRect r = src.rect();
17
18    r.inset(dx, dy);
19    if (r.isEmpty()) {
20        dst->setEmpty();
21        return;
22    }
23
24    SkVector radii[4];
25    for (int i = 0; i < 4; ++i) {
26        radii[i] = src.radii((SkRRect::Corner)i);
27    }
28    for (int i = 0; i < 4; ++i) {
29        radii[i].fX -= dx;
30        radii[i].fY -= dy;
31    }
32    dst->setRectRadii(r, radii);
33}
34
35static void inset1(const SkRRect& src, SkScalar dx, SkScalar dy, SkRRect* dst) {
36    SkRect r = src.rect();
37
38    r.inset(dx, dy);
39    if (r.isEmpty()) {
40        dst->setEmpty();
41        return;
42    }
43
44    SkVector radii[4];
45    for (int i = 0; i < 4; ++i) {
46        radii[i] = src.radii((SkRRect::Corner)i);
47    }
48    dst->setRectRadii(r, radii);
49}
50
51static void inset2(const SkRRect& src, SkScalar dx, SkScalar dy, SkRRect* dst) {
52    SkRect r = src.rect();
53
54    r.inset(dx, dy);
55    if (r.isEmpty()) {
56        dst->setEmpty();
57        return;
58    }
59
60    SkVector radii[4];
61    for (int i = 0; i < 4; ++i) {
62        radii[i] = src.radii((SkRRect::Corner)i);
63    }
64    for (int i = 0; i < 4; ++i) {
65        if (radii[i].fX) {
66            radii[i].fX -= dx;
67        }
68        if (radii[i].fY) {
69            radii[i].fY -= dy;
70        }
71    }
72    dst->setRectRadii(r, radii);
73}
74
75static SkScalar prop(SkScalar radius, SkScalar newSize, SkScalar oldSize) {
76    return newSize * radius / oldSize;
77}
78
79static void inset3(const SkRRect& src, SkScalar dx, SkScalar dy, SkRRect* dst) {
80    SkRect r = src.rect();
81
82    r.inset(dx, dy);
83    if (r.isEmpty()) {
84        dst->setEmpty();
85        return;
86    }
87
88    SkVector radii[4];
89    for (int i = 0; i < 4; ++i) {
90        radii[i] = src.radii((SkRRect::Corner)i);
91    }
92    for (int i = 0; i < 4; ++i) {
93        radii[i].fX = prop(radii[i].fX, r.width(), src.rect().width());
94        radii[i].fY = prop(radii[i].fY, r.height(), src.rect().height());
95    }
96    dst->setRectRadii(r, radii);
97}
98
99static void draw_rrect_color(SkCanvas* canvas, const SkRRect& rrect) {
100    SkPaint paint;
101    paint.setAntiAlias(true);
102    paint.setStyle(SkPaint::kStroke_Style);
103
104    if (rrect.isRect()) {
105        paint.setColor(SK_ColorRED);
106    } else if (rrect.isOval()) {
107        paint.setColor(0xFF008800);
108    } else if (rrect.isSimple()) {
109        paint.setColor(SK_ColorBLUE);
110    } else {
111        paint.setColor(SK_ColorBLACK);
112    }
113    canvas->drawRRect(rrect, paint);
114}
115
116static void drawrr(SkCanvas* canvas, const SkRRect& rrect, InsetProc proc) {
117    SkRRect rr;
118    for (SkScalar d = -30; d <= 30; d += 5) {
119        proc(rrect, d, d, &rr);
120        draw_rrect_color(canvas, rr);
121    }
122}
123
124class RRectGM : public skiagm::GM {
125public:
126    RRectGM() {}
127
128protected:
129    virtual uint32_t onGetFlags() const SK_OVERRIDE {
130        return kSkipTiled_Flag;
131    }
132
133    virtual SkString onShortName() {
134        return SkString("rrect");
135    }
136
137    virtual SkISize onISize() {
138        return SkISize::Make(820, 710);
139    }
140
141    virtual void onDraw(SkCanvas* canvas) {
142        static const InsetProc insetProcs[] = {
143            inset0, inset1, inset2, inset3
144        };
145
146        SkRRect rrect[4];
147        SkRect r = { 0, 0, 120, 100 };
148        SkVector radii[4] = {
149            { 0, 0 }, { 30, 1 }, { 10, 40 }, { 40, 40 }
150        };
151
152        rrect[0].setRect(r);
153        rrect[1].setOval(r);
154        rrect[2].setRectXY(r, 20, 20);
155        rrect[3].setRectRadii(r, radii);
156
157        canvas->translate(50.5f, 50.5f);
158        for (size_t j = 0; j < SK_ARRAY_COUNT(insetProcs); ++j) {
159            canvas->save();
160            for (size_t i = 0; i < SK_ARRAY_COUNT(rrect); ++i) {
161                drawrr(canvas, rrect[i], insetProcs[j]);
162                canvas->translate(200, 0);
163            }
164            canvas->restore();
165            canvas->translate(0, 170);
166        }
167    }
168
169private:
170    typedef GM INHERITED;
171};
172
173DEF_GM( return new RRectGM; )
174