1/*
2 * Copyright 2015 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
10#include "SkShader.h"
11
12// This class of GMs test how edges/verts snap near rounding boundaries in device space without
13// anti-aliaing.
14class PixelSnapGM : public skiagm::GM {
15public:
16    PixelSnapGM() {}
17
18protected:
19    // kTrans should be even or checkboards wont agree in different test cases.
20    static const int kTrans = 14;
21    static const int kLabelPad = 4;
22    // The inverse of this value should be a perfect SkScalar.
23    static const int kSubPixelSteps = 8;
24    static const int kLabelTextSize = 9;
25
26    SK_COMPILE_ASSERT(kSubPixelSteps < 99, label_offset_too_small);
27    static const int kLabelOffsetX = 2 * kLabelTextSize + kLabelPad;
28    static const int kLabelOffsetY = kLabelTextSize + kLabelPad;
29
30    SkISize onISize() override {
31        return SkISize::Make((kSubPixelSteps + 1) * kTrans + kLabelOffsetX + kLabelPad,
32                             (kSubPixelSteps + 1) * kTrans + kLabelOffsetY + kLabelPad);
33    }
34
35    void onDraw(SkCanvas* canvas) override {
36        SkPaint bgPaint;
37        bgPaint.setShader(
38            sk_tool_utils::create_checkerboard_shader(0xFFAAAAAA, 0xFF777777, 1))->unref();
39        canvas->drawPaint(bgPaint);
40
41        SkString offset;
42        SkPaint labelPaint;
43        labelPaint.setAntiAlias(true);
44        labelPaint.setColor(SK_ColorWHITE);
45        labelPaint.setTextSize(SkIntToScalar(kLabelTextSize));
46        SkPaint linePaint;
47        linePaint.setColor(SK_ColorWHITE);
48
49        // Drawing labels is useful for debugging, but bad for baselining (x-platform txt diffs).
50        if (false) {
51            // Draw row labels
52            canvas->save();
53                canvas->translate(0, SkIntToScalar(kLabelOffsetY));
54                for (int i = 0; i <= kSubPixelSteps; ++i) {
55                    offset.printf("%d", i);
56                    canvas->drawText(offset.c_str(), offset.size(),
57                                     0, i * kTrans + labelPaint.getTextSize(),
58                                     labelPaint);
59                }
60            canvas->restore();
61
62            // Draw col labels
63            canvas->save();
64                canvas->translate(SkIntToScalar(kLabelOffsetX), 0);
65                for (int i = 0; i <= kSubPixelSteps; ++i) {
66                    offset.printf("%d", i);
67                    canvas->drawText(offset.c_str(), offset.size(),
68                                     i * SkIntToScalar(kTrans), labelPaint.getTextSize(),
69                                     labelPaint);
70                }
71            canvas->restore();
72        }
73
74        canvas->translate(SkIntToScalar(kLabelOffsetX), SkIntToScalar(kLabelOffsetY));
75
76        // Draw test case grid lines (Draw them all at pixel centers to hopefully avoid any
77        // snapping issues).
78        for (int i = 0; i <= kSubPixelSteps + 1; ++i) {
79            canvas->drawLine(0.5f,
80                             i * SkIntToScalar(kTrans) + 0.5f,
81                             SkIntToScalar(kTrans) * (kSubPixelSteps + 1) + 0.5f,
82                             i * SkIntToScalar(kTrans) + 0.5f,
83                             linePaint);
84            canvas->drawLine(i * SkIntToScalar(kTrans) + 0.5f,
85                             0.5f,
86                             i * SkIntToScalar(kTrans) + 0.5f,
87                             SkIntToScalar(kTrans) * (kSubPixelSteps + 1) + 0.5f,
88                             linePaint);
89        }
90
91        for (int i = 0; i <= kSubPixelSteps; ++i) {
92            for (int j = 0; j <= kSubPixelSteps; ++j) {
93                canvas->save();
94                // +1's account for the grid lines around each test case.
95                canvas->translate(j * (kTrans + 1.f/kSubPixelSteps) + 1,
96                                  i * (kTrans + 1.f/kSubPixelSteps) + 1);
97                this->drawElement(canvas);
98                canvas->restore();
99            }
100        }
101    }
102
103    virtual void drawElement(SkCanvas*) = 0;
104
105private:
106    typedef skiagm::GM INHERITED;
107};
108
109class PointSnapGM : public PixelSnapGM {
110protected:
111    SkString onShortName() override { return SkString("pixel_snap_point"); }
112    void drawElement(SkCanvas* canvas) override { canvas->drawPoint(1, 1, SK_ColorBLUE); }
113
114private:
115    typedef PixelSnapGM INHERITED;
116};
117
118class LineSnapGM : public PixelSnapGM {
119protected:
120    SkString onShortName() override { return SkString("pixel_snap_line"); }
121    void drawElement(SkCanvas* canvas) override {
122        SkPaint paint;
123        paint.setColor(SK_ColorGREEN);
124        // Draw a horizontal and vertical line, each length 3.
125        canvas->drawLine(1, 1, 4, 1, paint);
126        canvas->drawLine(6, 1, 6, 4, paint);
127    }
128
129private:
130    typedef PixelSnapGM INHERITED;
131};
132
133class RectSnapGM : public PixelSnapGM {
134protected:
135    SkString onShortName() override { return SkString("pixel_snap_rect"); }
136    void drawElement(SkCanvas* canvas) override {
137        SkPaint paint;
138        paint.setColor(SK_ColorRED);
139        canvas->drawRect(SkRect::MakeXYWH(1, 1, 3, 3), paint);
140    }
141
142private:
143    typedef PixelSnapGM INHERITED;
144};
145
146class ComboSnapGM : public PixelSnapGM {
147protected:
148    SkString onShortName() override { return SkString("pixel_snap_combo"); }
149    void drawElement(SkCanvas* canvas) override {
150        SkPaint paint;
151        paint.setAntiAlias(false);
152        // A rectangle that exactly covers a pixel, a point at each corner, 8 horiz/vert lines
153        // at rect corners (two at each corner, extending away from rect). They are drawn in this
154        // order lines (green), points (blue), rect(red).
155        SkRect rect = SkRect::MakeXYWH(3, 3, 1, 1);
156        paint.setColor(SK_ColorGREEN);
157        canvas->drawLine(3, 3, 0, 3, paint);
158        canvas->drawLine(3, 3, 3, 0, paint);
159        canvas->drawLine(4, 3, 7, 3, paint);
160        canvas->drawLine(4, 3, 4, 0, paint);
161        canvas->drawLine(3, 4, 0, 4, paint);
162        canvas->drawLine(3, 4, 3, 7, paint);
163        canvas->drawLine(4, 4, 7, 4, paint);
164        canvas->drawLine(4, 4, 4, 7, paint);
165        canvas->drawPoint(4, 3, SK_ColorBLUE);
166        canvas->drawPoint(4, 4, SK_ColorBLUE);
167        canvas->drawPoint(3, 3, SK_ColorBLUE);
168        canvas->drawPoint(3, 4, SK_ColorBLUE);
169        paint.setColor(SK_ColorRED);
170        canvas->drawRect(rect, paint);
171    }
172
173private:
174    typedef PixelSnapGM INHERITED;
175};
176
177//////////////////////////////////////////////////////////////////////////////
178DEF_GM( return SkNEW(PointSnapGM); )
179DEF_GM( return SkNEW(LineSnapGM); )
180DEF_GM( return SkNEW(RectSnapGM); )
181DEF_GM( return SkNEW(ComboSnapGM); )
182