1 /* 2 * Copyright 2017 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 "SkPath.h" 11 12 namespace { 13 // Test thin stroked rect (stroked "by hand", not by stroking). 14 void draw_thin_stroked_rect(SkCanvas* canvas, const SkPaint& paint, SkScalar width) { 15 SkPath path; 16 path.moveTo(10 + width, 10 + width); 17 path.lineTo(40, 10 + width); 18 path.lineTo(40, 20); 19 path.lineTo(10 + width, 20); 20 path.moveTo(10, 10); 21 path.lineTo(10, 20 + width); 22 path.lineTo(40 + width, 20 + width); 23 path.lineTo(40 + width, 10); 24 canvas->drawPath(path, paint); 25 } 26 27 void draw_thin_right_angle(SkCanvas* canvas, const SkPaint& paint, SkScalar width) { 28 SkPath path; 29 path.moveTo(10 + width, 10 + width); 30 path.lineTo(40, 10 + width); 31 path.lineTo(40, 20); 32 path.lineTo(40 + width, 20 + width); 33 path.lineTo(40 + width, 10); 34 path.lineTo(10, 10); 35 canvas->drawPath(path, paint); 36 } 37 38 // Test thin horizontal line (<1 pixel) which should give lower alpha. 39 void draw_golf_club(SkCanvas* canvas, const SkPaint& paint, SkScalar width) { 40 SkPath path; 41 path.moveTo(20, 10); 42 path.lineTo(80, 10); 43 path.lineTo(80, 10 + width); 44 path.lineTo(30, 10 + width); 45 path.lineTo(30, 20); 46 path.lineTo(20, 20); 47 canvas->drawPath(path, paint); 48 } 49 50 // Test thin lines between two filled regions. The outer edges overlap, but 51 // there are no inverted edges to fix. 52 void draw_barbell(SkCanvas* canvas, const SkPaint& paint, SkScalar width) { 53 SkScalar offset = width * 0.5f; 54 SkPath path; 55 path.moveTo(30, 5); 56 path.lineTo(40 - offset, 15 - offset); 57 path.lineTo(60 + offset, 15 - offset); 58 path.lineTo(70, 5); 59 path.lineTo(70, 25); 60 path.lineTo(60 + offset, 15 + offset); 61 path.lineTo(40 - offset, 15 + offset); 62 path.lineTo(30, 25); 63 canvas->drawPath(path, paint); 64 } 65 66 // Test a thin rectangle and triangle. The top and bottom inner edges of the 67 // rectangle and all inner edges of the triangle invert on stroking. 68 void draw_thin_rect_and_triangle(SkCanvas* canvas, const SkPaint& paint, SkScalar width) { 69 SkPath path; 70 path.moveTo(30, 5); 71 path.lineTo(30 + width, 5); 72 path.lineTo(30 + width, 25); 73 path.lineTo(30, 25); 74 path.moveTo(40, 5); 75 path.lineTo(40 + width, 5); 76 path.lineTo(40, 25); 77 canvas->drawPath(path, paint); 78 } 79 80 // Two triangles joined by a very thin bridge. The tiny triangle formed 81 // by the inner edges at the bridge is inverted. 82 // (These are actually now more phat pants than hipster pants.) 83 void draw_hipster_pants(SkCanvas* canvas, const SkPaint& paint, SkScalar width) { 84 SkPath path; 85 path.moveTo(10, 10); 86 path.lineTo(10, 20); 87 path.lineTo(50, 10 + width); 88 path.lineTo(90, 20); 89 path.lineTo(90, 10); 90 canvas->drawPath(path, paint); 91 } 92 93 // A thin z-shape whose interior inverts on stroking. The top and bottom inner edges invert, and 94 // the connector edges at the "elbows" intersect the inner edges. 95 void draw_skinny_snake(SkCanvas* canvas, const SkPaint& paint, SkScalar width) { 96 SkPath path; 97 path.moveTo(20 + width, 10); 98 path.lineTo(20 + width, 20); 99 path.lineTo(10 + width, 30); 100 path.lineTo(10 + width, 40); 101 path.lineTo(10 - width, 40); 102 path.lineTo(10 - width, 30); 103 path.lineTo(20 - width, 20); 104 path.lineTo(20 - width, 10); 105 canvas->drawPath(path, paint); 106 } 107 108 // Test pointy features whose outer edges extend far to the right on stroking. 109 void draw_pointy_golf_club(SkCanvas* canvas, const SkPaint& paint, SkScalar width) { 110 SkPath path; 111 path.moveTo(20, 10); 112 path.lineTo(80, 10 + width * 0.5); 113 path.lineTo(30, 10 + width); 114 path.lineTo(30, 20); 115 path.lineTo(20, 20); 116 canvas->drawPath(path, paint); 117 } 118 119 }; 120 121 DEF_SIMPLE_GM(thinconcavepaths, canvas, 550, 400) { 122 SkPaint paint; 123 124 paint.setAntiAlias(true); 125 paint.setStyle(SkPaint::kFill_Style); 126 127 canvas->save(); 128 for (SkScalar width = 0.5f; width < 2.05f; width += 0.25f) { 129 draw_thin_stroked_rect(canvas, paint, width); 130 canvas->translate(0, 25); 131 } 132 canvas->restore(); 133 canvas->translate(50, 0); 134 canvas->save(); 135 for (SkScalar width = 0.5f; width < 2.05f; width += 0.25f) { 136 draw_thin_right_angle(canvas, paint, width); 137 canvas->translate(0, 25); 138 } 139 canvas->restore(); 140 canvas->translate(40, 0); 141 canvas->save(); 142 for (SkScalar width = 0.2f; width < 2.1f; width += 0.2f) { 143 draw_golf_club(canvas, paint, width); 144 canvas->translate(0, 30); 145 } 146 canvas->restore(); 147 canvas->translate(70, 0); 148 canvas->save(); 149 for (SkScalar width = 0.2f; width < 2.1f; width += 0.2f) { 150 draw_thin_rect_and_triangle(canvas, paint, width); 151 canvas->translate(0, 30); 152 } 153 canvas->restore(); 154 canvas->translate(30, 0); 155 canvas->save(); 156 157 for (SkScalar width = 0.2f; width < 2.1f; width += 0.2f) { 158 draw_barbell(canvas, paint, width); 159 canvas->translate(0, 30); 160 } 161 canvas->restore(); 162 canvas->translate(80, 0); 163 canvas->save(); 164 for (SkScalar width = 0.2f; width < 2.1f; width += 0.2f) { 165 draw_hipster_pants(canvas, paint, width); 166 canvas->translate(0, 30); 167 } 168 canvas->restore(); 169 canvas->translate(100, 0); 170 canvas->save(); 171 for (SkScalar width = 0.2f; width < 2.1f; width += 0.2f) { 172 draw_skinny_snake(canvas, paint, width); 173 canvas->translate(0, 30); 174 } 175 canvas->restore(); 176 canvas->translate(30, 0); 177 canvas->save(); 178 for (SkScalar width = 0.2f; width < 2.1f; width += 0.2f) { 179 draw_pointy_golf_club(canvas, paint, width); 180 canvas->translate(0, 30); 181 } 182 canvas->restore(); 183 canvas->translate(100, 0); 184 } 185