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: PixelSnapGM()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 onISize()31 SkISize onISize() override { 32 return SkISize::Make((kSubPixelSteps + 1) * kTrans + kLabelOffsetX + kLabelPad, 33 (kSubPixelSteps + 1) * kTrans + kLabelOffsetY + kLabelPad); 34 } 35 onDraw(SkCanvas * canvas)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: onShortName()106 SkString onShortName() override { return SkString("pixel_snap_point"); } drawElement(SkCanvas * canvas)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: onShortName()120 SkString onShortName() override { return SkString("pixel_snap_line"); } drawElement(SkCanvas * canvas)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: onShortName()135 SkString onShortName() override { return SkString("pixel_snap_rect"); } drawElement(SkCanvas * canvas)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: onShortName()148 SkString onShortName() override { return SkString("pixel_snap_combo"); } drawElement(SkCanvas * canvas)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