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