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