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