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( 40 sk_tool_utils::color_to_565(0xFFAAAAAA), 41 sk_tool_utils::color_to_565(0xFF777777), 1)); 42 canvas->drawPaint(bgPaint); 43 44 SkString offset; 45 SkPaint labelPaint; 46 labelPaint.setAntiAlias(true); 47 labelPaint.setColor(SK_ColorWHITE); 48 labelPaint.setTextSize(SkIntToScalar(kLabelTextSize)); 49 sk_tool_utils::set_portable_typeface(&labelPaint); 50 SkPaint linePaint; 51 linePaint.setColor(SK_ColorWHITE); 52 53 // Draw row labels 54 canvas->save(); 55 canvas->translate(0, SkIntToScalar(kLabelOffsetY)); 56 for (int i = 0; i <= kSubPixelSteps; ++i) { 57 offset.printf("%d", i); 58 canvas->drawText(offset.c_str(), offset.size(), 59 0, i * kTrans + labelPaint.getTextSize(), 60 labelPaint); 61 } 62 canvas->restore(); 63 64 // Draw col labels 65 canvas->save(); 66 canvas->translate(SkIntToScalar(kLabelOffsetX), 0); 67 for (int i = 0; i <= kSubPixelSteps; ++i) { 68 offset.printf("%d", i); 69 canvas->drawText(offset.c_str(), offset.size(), 70 i * SkIntToScalar(kTrans), labelPaint.getTextSize(), 71 labelPaint); 72 } 73 canvas->restore(); 74 75 canvas->translate(SkIntToScalar(kLabelOffsetX), SkIntToScalar(kLabelOffsetY)); 76 77 // Draw test case grid lines (Draw them all at pixel centers to hopefully avoid any 78 // snapping issues). 79 for (int i = 0; i <= kSubPixelSteps + 1; ++i) { 80 canvas->drawLine(0.5f, 81 i * SkIntToScalar(kTrans) + 0.5f, 82 SkIntToScalar(kTrans) * (kSubPixelSteps + 1) + 0.5f, 83 i * SkIntToScalar(kTrans) + 0.5f, 84 linePaint); 85 canvas->drawLine(i * SkIntToScalar(kTrans) + 0.5f, 86 0.5f, 87 i * SkIntToScalar(kTrans) + 0.5f, 88 SkIntToScalar(kTrans) * (kSubPixelSteps + 1) + 0.5f, 89 linePaint); 90 } 91 92 for (int i = 0; i <= kSubPixelSteps; ++i) { 93 for (int j = 0; j <= kSubPixelSteps; ++j) { 94 canvas->save(); 95 // +1's account for the grid lines around each test case. 96 canvas->translate(j * (kTrans + 1.f/kSubPixelSteps) + 1, 97 i * (kTrans + 1.f/kSubPixelSteps) + 1); 98 this->drawElement(canvas); 99 canvas->restore(); 100 } 101 } 102 } 103 104 virtual void drawElement(SkCanvas*) = 0; 105 106 private: 107 typedef skiagm::GM INHERITED; 108 }; 109 110 class PointSnapGM : public PixelSnapGM { 111 protected: 112 SkString onShortName() override { return SkString("pixel_snap_point"); } 113 void drawElement(SkCanvas* canvas) override { 114 const SkPoint pt = { 1, 1 }; 115 SkPaint paint; 116 paint.setColor(SK_ColorBLUE); 117 canvas->drawPoints(SkCanvas::kPoints_PointMode, 1, &pt, paint); 118 } 119 120 private: 121 typedef PixelSnapGM INHERITED; 122 }; 123 124 class LineSnapGM : public PixelSnapGM { 125 protected: 126 SkString onShortName() override { return SkString("pixel_snap_line"); } 127 void drawElement(SkCanvas* canvas) override { 128 SkPaint paint; 129 paint.setColor(SK_ColorGREEN); 130 // Draw a horizontal and vertical line, each length 3. 131 canvas->drawLine(1, 1, 4, 1, paint); 132 canvas->drawLine(6, 1, 6, 4, paint); 133 } 134 135 private: 136 typedef PixelSnapGM INHERITED; 137 }; 138 139 class RectSnapGM : public PixelSnapGM { 140 protected: 141 SkString onShortName() override { return SkString("pixel_snap_rect"); } 142 void drawElement(SkCanvas* canvas) override { 143 SkPaint paint; 144 paint.setColor(SK_ColorRED); 145 canvas->drawRect(SkRect::MakeXYWH(1, 1, 3, 3), paint); 146 } 147 148 private: 149 typedef PixelSnapGM INHERITED; 150 }; 151 152 class ComboSnapGM : public PixelSnapGM { 153 protected: 154 SkString onShortName() override { return SkString("pixel_snap_combo"); } 155 void drawElement(SkCanvas* canvas) override { 156 SkPaint paint; 157 paint.setAntiAlias(false); 158 // A rectangle that exactly covers a pixel, a point at each corner, 8 horiz/vert lines 159 // at rect corners (two at each corner, extending away from rect). They are drawn in this 160 // order lines (green), points (blue), rect(red). 161 SkRect rect = SkRect::MakeXYWH(3, 3, 1, 1); 162 paint.setColor(SK_ColorGREEN); 163 const SkPoint lines[] = { 164 { 3, 3 }, { 0, 3 }, 165 { 3, 3 }, { 3, 0 }, 166 { 4, 3 }, { 7, 3 }, 167 { 4, 3 }, { 4, 0 }, 168 { 3, 4 }, { 0, 4 }, 169 { 3, 4 }, { 3, 7 }, 170 { 4, 4 }, { 7, 4 }, 171 { 4, 4 }, { 4, 7 }, 172 }; 173 canvas->drawPoints(SkCanvas::kLines_PointMode, SK_ARRAY_COUNT(lines), lines, paint); 174 175 const SkPoint pts[] = { 176 { 4, 3 }, { 4, 4, }, { 3, 3 }, { 3, 4 }, 177 }; 178 paint.setColor(SK_ColorBLUE); 179 canvas->drawPoints(SkCanvas::kPoints_PointMode, SK_ARRAY_COUNT(pts), pts, paint); 180 181 paint.setColor(SK_ColorRED); 182 canvas->drawRect(rect, paint); 183 } 184 185 private: 186 typedef PixelSnapGM INHERITED; 187 }; 188 189 ////////////////////////////////////////////////////////////////////////////// 190 DEF_GM(return new PointSnapGM;) 191 DEF_GM(return new LineSnapGM;) 192 DEF_GM(return new RectSnapGM;) 193 DEF_GM(return new ComboSnapGM;) 194