Home | History | Annotate | Download | only in gm
      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 #include "sk_tool_utils.h"
     10 
     11 #include "SkShader.h"
     12 
     13 // This class of GMs test how edges/verts snap near rounding boundaries in device space without
     14 // anti-aliaing.
     15 class PixelSnapGM : public skiagm::GM {
     16 public:
     17     PixelSnapGM() {}
     18 
     19 protected:
     20     // kTrans should be even or checkboards wont agree in different test cases.
     21     static constexpr int kTrans = 14;
     22     static constexpr int kLabelPad = 4;
     23     // The inverse of this value should be a perfect SkScalar.
     24     static constexpr int kSubPixelSteps = 8;
     25     static constexpr int kLabelTextSize = 9;
     26 
     27     static_assert(kSubPixelSteps < 99, "label_offset_too_small");
     28     static constexpr int kLabelOffsetX = 2 * kLabelTextSize + kLabelPad;
     29     static constexpr int kLabelOffsetY = kLabelTextSize + kLabelPad;
     30 
     31     SkISize onISize() override {
     32         return SkISize::Make((kSubPixelSteps + 1) * kTrans + kLabelOffsetX + kLabelPad,
     33                              (kSubPixelSteps + 1) * kTrans + kLabelOffsetY + kLabelPad);
     34     }
     35 
     36     void onDraw(SkCanvas* canvas) override {
     37         SkPaint bgPaint;
     38         bgPaint.setShader(
     39                 sk_tool_utils::create_checkerboard_shader(0xFFAAAAAA, 0xFF777777, 1));
     40         canvas->drawPaint(bgPaint);
     41 
     42         SkString offset;
     43         SkPaint labelPaint;
     44         labelPaint.setColor(SK_ColorWHITE);
     45         SkFont font(sk_tool_utils::create_portable_typeface(), SkIntToScalar(kLabelTextSize));
     46         SkPaint linePaint;
     47         linePaint.setColor(SK_ColorWHITE);
     48 
     49         // Draw row labels
     50         canvas->save();
     51             canvas->translate(0, SkIntToScalar(kLabelOffsetY));
     52             for (int i = 0; i <= kSubPixelSteps; ++i) {
     53                 offset.printf("%d", i);
     54                 canvas->drawString(offset, 0, i * kTrans + SkIntToScalar(kLabelTextSize),
     55                                    font, labelPaint);
     56             }
     57         canvas->restore();
     58 
     59         // Draw col labels
     60         canvas->save();
     61             canvas->translate(SkIntToScalar(kLabelOffsetX), 0);
     62             for (int i = 0; i <= kSubPixelSteps; ++i) {
     63                 offset.printf("%d", i);
     64                 canvas->drawString(offset, i * SkIntToScalar(kTrans), SkIntToScalar(kLabelTextSize),
     65                                    font, labelPaint);
     66             }
     67         canvas->restore();
     68 
     69         canvas->translate(SkIntToScalar(kLabelOffsetX), SkIntToScalar(kLabelOffsetY));
     70 
     71         // Draw test case grid lines (Draw them all at pixel centers to hopefully avoid any
     72         // snapping issues).
     73         for (int i = 0; i <= kSubPixelSteps + 1; ++i) {
     74             canvas->drawLine(0.5f,
     75                              i * SkIntToScalar(kTrans) + 0.5f,
     76                              SkIntToScalar(kTrans) * (kSubPixelSteps + 1) + 0.5f,
     77                              i * SkIntToScalar(kTrans) + 0.5f,
     78                              linePaint);
     79             canvas->drawLine(i * SkIntToScalar(kTrans) + 0.5f,
     80                              0.5f,
     81                              i * SkIntToScalar(kTrans) + 0.5f,
     82                              SkIntToScalar(kTrans) * (kSubPixelSteps + 1) + 0.5f,
     83                              linePaint);
     84         }
     85 
     86         for (int i = 0; i <= kSubPixelSteps; ++i) {
     87             for (int j = 0; j <= kSubPixelSteps; ++j) {
     88                 canvas->save();
     89                 // +1's account for the grid lines around each test case.
     90                 canvas->translate(j * (kTrans + 1.f/kSubPixelSteps) + 1,
     91                                   i * (kTrans + 1.f/kSubPixelSteps) + 1);
     92                 this->drawElement(canvas);
     93                 canvas->restore();
     94             }
     95         }
     96     }
     97 
     98     virtual void drawElement(SkCanvas*) = 0;
     99 
    100 private:
    101     typedef skiagm::GM INHERITED;
    102 };
    103 
    104 class PointSnapGM : public PixelSnapGM {
    105 protected:
    106     SkString onShortName() override { return SkString("pixel_snap_point"); }
    107     void drawElement(SkCanvas* canvas) override {
    108         const SkPoint pt = { 1, 1 };
    109         SkPaint paint;
    110         paint.setColor(SK_ColorBLUE);
    111         canvas->drawPoints(SkCanvas::kPoints_PointMode, 1, &pt, paint);
    112     }
    113 
    114 private:
    115     typedef PixelSnapGM INHERITED;
    116 };
    117 
    118 class LineSnapGM : public PixelSnapGM {
    119 protected:
    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 
    129 private:
    130     typedef PixelSnapGM INHERITED;
    131 };
    132 
    133 class RectSnapGM : public PixelSnapGM {
    134 protected:
    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 
    142 private:
    143     typedef PixelSnapGM INHERITED;
    144 };
    145 
    146 class ComboSnapGM : public PixelSnapGM {
    147 protected:
    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         const SkPoint lines[] = {
    158             { 3, 3 }, { 0, 3 },
    159             { 3, 3 }, { 3, 0 },
    160             { 4, 3 }, { 7, 3 },
    161             { 4, 3 }, { 4, 0 },
    162             { 3, 4 }, { 0, 4 },
    163             { 3, 4 }, { 3, 7 },
    164             { 4, 4 }, { 7, 4 },
    165             { 4, 4 }, { 4, 7 },
    166         };
    167         canvas->drawPoints(SkCanvas::kLines_PointMode, SK_ARRAY_COUNT(lines), lines, paint);
    168 
    169         const SkPoint pts[] = {
    170             { 4, 3 }, { 4, 4, }, { 3, 3 }, { 3, 4 },
    171         };
    172         paint.setColor(SK_ColorBLUE);
    173         canvas->drawPoints(SkCanvas::kPoints_PointMode, SK_ARRAY_COUNT(pts), pts, paint);
    174 
    175         paint.setColor(SK_ColorRED);
    176         canvas->drawRect(rect, paint);
    177     }
    178 
    179 private:
    180     typedef PixelSnapGM INHERITED;
    181 };
    182 
    183 //////////////////////////////////////////////////////////////////////////////
    184 DEF_GM(return new PointSnapGM;)
    185 DEF_GM(return new LineSnapGM;)
    186 DEF_GM(return new RectSnapGM;)
    187 DEF_GM(return new ComboSnapGM;)
    188