1 /* 2 * Copyright 2011 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 "Sample.h" 9 #include "SkAnimTimer.h" 10 #include "SkBitmap.h" 11 #include "SkCanvas.h" 12 #include "SkColorFilter.h" 13 #include "SkColorPriv.h" 14 #include "SkCornerPathEffect.h" 15 #include "SkGradientShader.h" 16 #include "SkGraphics.h" 17 #include "SkPath.h" 18 #include "SkRandom.h" 19 #include "SkRegion.h" 20 #include "SkShader.h" 21 #include "SkStream.h" 22 #include "SkTime.h" 23 #include "SkTo.h" 24 #include "SkTypeface.h" 25 #include "SkUTF.h" 26 27 static SkRandom gRand; 28 29 static void generate_pts(SkPoint pts[], int count, int w, int h) { 30 for (int i = 0; i < count; i++) { 31 pts[i].set(gRand.nextUScalar1() * 3 * w - SkIntToScalar(w), 32 gRand.nextUScalar1() * 3 * h - SkIntToScalar(h)); 33 } 34 } 35 36 static bool check_zeros(const SkPMColor pixels[], int count, int skip) { 37 for (int i = 0; i < count; i++) { 38 if (*pixels) { 39 return false; 40 } 41 pixels += skip; 42 } 43 return true; 44 } 45 46 static bool check_bitmap_margin(const SkBitmap& bm, int margin) { 47 size_t rb = bm.rowBytes(); 48 for (int i = 0; i < margin; i++) { 49 if (!check_zeros(bm.getAddr32(0, i), bm.width(), 1)) { 50 return false; 51 } 52 int bottom = bm.height() - i - 1; 53 if (!check_zeros(bm.getAddr32(0, bottom), bm.width(), 1)) { 54 return false; 55 } 56 // left column 57 if (!check_zeros(bm.getAddr32(i, 0), bm.height(), SkToInt(rb >> 2))) { 58 return false; 59 } 60 int right = bm.width() - margin + i; 61 if (!check_zeros(bm.getAddr32(right, 0), bm.height(), 62 SkToInt(rb >> 2))) { 63 return false; 64 } 65 } 66 return true; 67 } 68 69 #define WIDTH 620 70 #define HEIGHT 460 71 #define MARGIN 10 72 73 static void line_proc(SkCanvas* canvas, const SkPaint& paint, 74 const SkBitmap& bm) { 75 const int N = 2; 76 SkPoint pts[N]; 77 for (int i = 0; i < 400; i++) { 78 generate_pts(pts, N, WIDTH, HEIGHT); 79 80 canvas->drawLine(pts[0], pts[1], paint); 81 if (!check_bitmap_margin(bm, MARGIN)) { 82 SkDebugf("---- hairline failure (%g %g) (%g %g)\n", 83 pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY); 84 break; 85 } 86 } 87 } 88 89 static void poly_proc(SkCanvas* canvas, const SkPaint& paint, 90 const SkBitmap& bm) { 91 const int N = 8; 92 SkPoint pts[N]; 93 for (int i = 0; i < 50; i++) { 94 generate_pts(pts, N, WIDTH, HEIGHT); 95 96 SkPath path; 97 path.moveTo(pts[0]); 98 for (int j = 1; j < N; j++) { 99 path.lineTo(pts[j]); 100 } 101 canvas->drawPath(path, paint); 102 } 103 } 104 105 static SkPoint ave(const SkPoint& a, const SkPoint& b) { 106 SkPoint c = a + b; 107 c.fX = SkScalarHalf(c.fX); 108 c.fY = SkScalarHalf(c.fY); 109 return c; 110 } 111 112 static void quad_proc(SkCanvas* canvas, const SkPaint& paint, 113 const SkBitmap& bm) { 114 const int N = 30; 115 SkPoint pts[N]; 116 for (int i = 0; i < 10; i++) { 117 generate_pts(pts, N, WIDTH, HEIGHT); 118 119 SkPath path; 120 path.moveTo(pts[0]); 121 for (int j = 1; j < N - 2; j++) { 122 path.quadTo(pts[j], ave(pts[j], pts[j+1])); 123 } 124 path.quadTo(pts[N - 2], pts[N - 1]); 125 126 canvas->drawPath(path, paint); 127 } 128 } 129 130 static void add_cubic(SkPath* path, const SkPoint& mid, const SkPoint& end) { 131 SkPoint start; 132 path->getLastPt(&start); 133 path->cubicTo(ave(start, mid), ave(mid, end), end); 134 } 135 136 static void cube_proc(SkCanvas* canvas, const SkPaint& paint, 137 const SkBitmap& bm) { 138 const int N = 30; 139 SkPoint pts[N]; 140 for (int i = 0; i < 10; i++) { 141 generate_pts(pts, N, WIDTH, HEIGHT); 142 143 SkPath path; 144 path.moveTo(pts[0]); 145 for (int j = 1; j < N - 2; j++) { 146 add_cubic(&path, pts[j], ave(pts[j], pts[j+1])); 147 } 148 add_cubic(&path, pts[N - 2], pts[N - 1]); 149 150 canvas->drawPath(path, paint); 151 } 152 } 153 154 typedef void (*HairProc)(SkCanvas*, const SkPaint&, const SkBitmap&); 155 156 static const struct { 157 const char* fName; 158 HairProc fProc; 159 } gProcs[] = { 160 { "line", line_proc }, 161 { "poly", poly_proc }, 162 { "quad", quad_proc }, 163 { "cube", cube_proc }, 164 }; 165 166 static int cycle_hairproc_index(int index) { 167 return (index + 1) % SK_ARRAY_COUNT(gProcs); 168 } 169 170 class HairlineView : public Sample { 171 SkMSec fNow; 172 int fProcIndex; 173 bool fDoAA; 174 public: 175 HairlineView() { 176 fProcIndex = 0; 177 fDoAA = true; 178 fNow = 0; 179 } 180 181 protected: 182 bool onQuery(Sample::Event* evt) override { 183 if (Sample::TitleQ(*evt)) { 184 SkString str; 185 str.printf("Hair-%s", gProcs[fProcIndex].fName); 186 Sample::TitleR(evt, str.c_str()); 187 return true; 188 } 189 return this->INHERITED::onQuery(evt); 190 } 191 192 void show_bitmaps(SkCanvas* canvas, const SkBitmap& b0, const SkBitmap& b1, 193 const SkIRect& inset) { 194 canvas->drawBitmap(b0, 0, 0, nullptr); 195 canvas->drawBitmap(b1, SkIntToScalar(b0.width()), 0, nullptr); 196 } 197 198 void onDrawContent(SkCanvas* canvas) override { 199 gRand.setSeed(fNow); 200 201 SkBitmap bm, bm2; 202 bm.allocN32Pixels(WIDTH + MARGIN*2, HEIGHT + MARGIN*2); 203 // this will erase our margin, which we want to always stay 0 204 bm.eraseColor(SK_ColorTRANSPARENT); 205 206 bm2.installPixels(SkImageInfo::MakeN32Premul(WIDTH, HEIGHT), 207 bm.getAddr32(MARGIN, MARGIN), bm.rowBytes()); 208 209 SkCanvas c2(bm2); 210 SkPaint paint; 211 paint.setAntiAlias(fDoAA); 212 paint.setStyle(SkPaint::kStroke_Style); 213 214 bm2.eraseColor(SK_ColorTRANSPARENT); 215 gProcs[fProcIndex].fProc(&c2, paint, bm); 216 canvas->drawBitmap(bm2, SkIntToScalar(10), SkIntToScalar(10), nullptr); 217 } 218 219 bool onAnimate(const SkAnimTimer&) override { 220 if (fDoAA) { 221 fProcIndex = cycle_hairproc_index(fProcIndex); 222 // todo: signal that we want to rebuild our TITLE 223 } 224 fDoAA = !fDoAA; 225 return true; 226 } 227 228 Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override { 229 fDoAA = !fDoAA; 230 return this->INHERITED::onFindClickHandler(x, y, modi); 231 } 232 233 234 private: 235 typedef Sample INHERITED; 236 }; 237 238 ////////////////////////////////////////////////////////////////////////////// 239 240 DEF_SAMPLE( return new HairlineView(); ) 241