OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright 2016 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 |
| 9 /* |
| 10 * This GM exercises stroking of paths with large stroke lengths, which is |
| 11 * referred to as "overstroke" for brevity. In Skia as of 8/2016 we offset |
| 12 * each part of the curve the request amount even if it makes the offsets |
| 13 * overlap and create holes. There is not a really great algorithm for this |
| 14 * and several other 2D graphics engines have the same bug. |
| 15 * |
| 16 * See crbug.com/589769 skbug.com/5405 skbug.com/5406 |
| 17 */ |
| 18 |
| 19 |
| 20 #include "gm.h" |
| 21 #include "SkPaint.h" |
| 22 #include "SkPath.h" |
| 23 |
| 24 //////// path and paint builders |
| 25 |
| 26 SkPaint make_overstroke_paint() { |
| 27 SkPaint p; |
| 28 p.setAntiAlias(true); |
| 29 p.setStyle(SkPaint::kStroke_Style); |
| 30 p.setStrokeWidth(500); |
| 31 |
| 32 return p; |
| 33 } |
| 34 |
| 35 SkPath quad_path() { |
| 36 SkPath path; |
| 37 path.moveTo(0, 0); |
| 38 path.lineTo(100, 0); |
| 39 path.quadTo(50, -40, |
| 40 0, 0); |
| 41 |
| 42 return path; |
| 43 } |
| 44 |
| 45 SkPath cubic_path() { |
| 46 SkPath path; |
| 47 path.moveTo(0, 0); |
| 48 path.cubicTo(25, 75, |
| 49 75, -50, |
| 50 100, 0); |
| 51 |
| 52 return path; |
| 53 } |
| 54 |
| 55 SkPath oval_path() { |
| 56 SkRect oval = SkRect::MakeXYWH(0, -25, 100, 50); |
| 57 |
| 58 SkPath path; |
| 59 path.arcTo(oval, 0, 359, true); |
| 60 path.close(); |
| 61 |
| 62 return path; |
| 63 } |
| 64 |
| 65 ///////// quads |
| 66 |
| 67 void draw_small_quad(SkCanvas *canvas) { |
| 68 // scaled so it's visible |
| 69 canvas->scale(8, 8); |
| 70 |
| 71 SkPaint p; |
| 72 p.setAntiAlias(true); |
| 73 p.setStyle(SkPaint::kStroke_Style); |
| 74 p.setStrokeWidth(3); |
| 75 |
| 76 SkPath path = quad_path(); |
| 77 |
| 78 canvas->drawPath(path, p); |
| 79 } |
| 80 |
| 81 void draw_large_quad(SkCanvas *canvas) { |
| 82 SkPaint p = make_overstroke_paint(); |
| 83 SkPath path = quad_path(); |
| 84 |
| 85 canvas->drawPath(path, p); |
| 86 } |
| 87 |
| 88 void draw_quad_fillpath(SkCanvas *canvas) { |
| 89 SkPath path = quad_path(); |
| 90 SkPaint p = make_overstroke_paint(); |
| 91 |
| 92 SkPaint fillp; |
| 93 fillp.setAntiAlias(true); |
| 94 fillp.setStyle(SkPaint::kStroke_Style); |
| 95 fillp.setColor(SK_ColorMAGENTA); |
| 96 |
| 97 SkPath fillpath; |
| 98 p.getFillPath(path, &fillpath); |
| 99 |
| 100 canvas->drawPath(fillpath, fillp); |
| 101 } |
| 102 |
| 103 void draw_stroked_quad(SkCanvas *canvas) { |
| 104 canvas->translate(200, 0); |
| 105 draw_large_quad(canvas); |
| 106 draw_quad_fillpath(canvas); |
| 107 } |
| 108 |
| 109 ////////// cubics |
| 110 |
| 111 void draw_small_cubic(SkCanvas *canvas) { |
| 112 // scaled so it's visible |
| 113 canvas->scale(8, 8); |
| 114 |
| 115 SkPaint p; |
| 116 p.setAntiAlias(true); |
| 117 p.setStyle(SkPaint::kStroke_Style); |
| 118 p.setStrokeWidth(3); |
| 119 |
| 120 SkPath path = cubic_path(); |
| 121 |
| 122 canvas->drawPath(path, p); |
| 123 } |
| 124 |
| 125 void draw_large_cubic(SkCanvas *canvas) { |
| 126 SkPaint p = make_overstroke_paint(); |
| 127 SkPath path = cubic_path(); |
| 128 |
| 129 canvas->drawPath(path, p); |
| 130 } |
| 131 |
| 132 void draw_cubic_fillpath(SkCanvas *canvas) { |
| 133 SkPath path = cubic_path(); |
| 134 SkPaint p = make_overstroke_paint(); |
| 135 |
| 136 SkPaint fillp; |
| 137 fillp.setAntiAlias(true); |
| 138 fillp.setStyle(SkPaint::kStroke_Style); |
| 139 fillp.setColor(SK_ColorMAGENTA); |
| 140 |
| 141 SkPath fillpath; |
| 142 p.getFillPath(path, &fillpath); |
| 143 |
| 144 canvas->drawPath(fillpath, fillp); |
| 145 } |
| 146 |
| 147 void draw_stroked_cubic(SkCanvas *canvas) { |
| 148 canvas->translate(400, 0); |
| 149 draw_large_cubic(canvas); |
| 150 draw_cubic_fillpath(canvas); |
| 151 } |
| 152 |
| 153 ////////// ovals |
| 154 |
| 155 void draw_small_oval(SkCanvas *canvas) { |
| 156 // scaled so it's visible |
| 157 canvas->scale(8, 8); |
| 158 |
| 159 SkPaint p; |
| 160 p.setAntiAlias(true); |
| 161 p.setStyle(SkPaint::kStroke_Style); |
| 162 p.setStrokeWidth(3); |
| 163 |
| 164 SkPath path = oval_path(); |
| 165 |
| 166 canvas->drawPath(path, p); |
| 167 } |
| 168 |
| 169 void draw_large_oval(SkCanvas *canvas) { |
| 170 SkPaint p = make_overstroke_paint(); |
| 171 SkPath path = oval_path(); |
| 172 |
| 173 canvas->drawPath(path, p); |
| 174 } |
| 175 |
| 176 void draw_oval_fillpath(SkCanvas *canvas) { |
| 177 SkPath path = oval_path(); |
| 178 SkPaint p = make_overstroke_paint(); |
| 179 |
| 180 SkPaint fillp; |
| 181 fillp.setAntiAlias(true); |
| 182 fillp.setStyle(SkPaint::kStroke_Style); |
| 183 fillp.setColor(SK_ColorMAGENTA); |
| 184 |
| 185 SkPath fillpath; |
| 186 p.getFillPath(path, &fillpath); |
| 187 |
| 188 canvas->drawPath(fillpath, fillp); |
| 189 } |
| 190 |
| 191 void draw_stroked_oval(SkCanvas *canvas) { |
| 192 canvas->translate(400, 0); |
| 193 draw_large_oval(canvas); |
| 194 draw_oval_fillpath(canvas); |
| 195 } |
| 196 |
| 197 ////////// gm |
| 198 |
| 199 void (*examples[])(SkCanvas *canvas) = { |
| 200 draw_small_quad, draw_stroked_quad, draw_small_cubic, |
| 201 draw_stroked_cubic, draw_small_oval, draw_stroked_oval, |
| 202 }; |
| 203 |
| 204 DEF_SIMPLE_GM(OverStroke, canvas, 500, 500) { |
| 205 const size_t length = sizeof(examples) / sizeof(examples[0]); |
| 206 const size_t width = 2; |
| 207 |
| 208 for (size_t i = 0; i < length; i++) { |
| 209 int x = (int)(i % width); |
| 210 int y = (int)(i / width); |
| 211 |
| 212 canvas->save(); |
| 213 canvas->translate(200.0f * x, 150.0f * y); |
| 214 canvas->scale(0.25f, 0.25f); |
| 215 canvas->translate(100.0f, 400.0f); |
| 216 |
| 217 examples[i](canvas); |
| 218 |
| 219 canvas->restore(); |
| 220 } |
| 221 } |
OLD | NEW |