blob: 8acb7f5610a9f795e69beb5689bbdc71f2486450 [file] [log] [blame]
mike@reedtribe.org50e4c722012-10-22 03:59:34 +00001/*
2 * Copyright 2012 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 "SkPath.h"
12#include "SkRegion.h"
13#include "SkShader.h"
14#include "SkUtils.h"
15#include "SkImage.h"
16#include "SkSurface.h"
17
18static void erase(SkSurface* surface) {
19 surface->getCanvas()->clear(0);
20}
21
22static SkShader* createChecker() {
23 SkBitmap bm;
24 bm.setConfig(SkBitmap::kARGB_8888_Config, 2, 2);
25 bm.allocPixels();
26 bm.lockPixels();
27 *bm.getAddr32(0, 0) = *bm.getAddr32(1, 1) = SkPreMultiplyColor(0xFFFDFDFD);
28 *bm.getAddr32(0, 1) = *bm.getAddr32(1, 0) = SkPreMultiplyColor(0xFFF4F4F4);
29 SkShader* s = SkShader::CreateBitmapShader(bm, SkShader::kRepeat_TileMode,
30 SkShader::kRepeat_TileMode);
31
32 SkMatrix m;
33 m.setScale(12, 12);
34 s->setLocalMatrix(m);
35 return s;
36}
37
38class FatBits {
39public:
40 FatBits() : fShader(createChecker()) {
41 fAA = false;
42 fStyle = kHair_Style;
43 fGrid = true;
44 }
45
46 bool getAA() const { return fAA; }
47 void setAA(bool aa) { fAA = aa; }
48
49 bool getGrid() const { return fGrid; }
50 void setGrid(bool g) { fGrid = g; }
51
52 enum Style {
53 kHair_Style,
54 kStroke_Style
55 };
56 Style getStyle() const { return fStyle; }
57 void setStyle(Style s) { fStyle = s; }
58
59 void setWHZ(int width, int height, int zoom) {
60 fW = width;
61 fH = height;
62 fZ = zoom;
63 fBounds.set(0, 0, SkIntToScalar(width * zoom), SkIntToScalar(height * zoom));
64 fMatrix.setScale(SkIntToScalar(zoom), SkIntToScalar(zoom));
65 fInverse.setScale(SK_Scalar1 / zoom, SK_Scalar1 / zoom);
66 fShader->setLocalMatrix(fMatrix);
67
68 SkImage::Info info = {
69 width, height, SkImage::kPMColor_ColorType, SkImage::kPremul_AlphaType
70 };
71 fMinSurface.reset(SkSurface::NewRaster(info, NULL));
72 info.fWidth *= zoom;
73 info.fHeight *= zoom;
74 fMaxSurface.reset(SkSurface::NewRaster(info, NULL));
75 }
76
77 void drawBG(SkCanvas*);
78 void drawFG(SkCanvas*);
79 void drawLine(SkCanvas*, SkPoint pts[2]);
80 void drawRect(SkCanvas* canvas, SkPoint pts[2]);
81
82private:
83 bool fAA, fGrid;
84 Style fStyle;
85 int fW, fH, fZ;
86 SkMatrix fMatrix, fInverse;
87 SkRect fBounds;
88 SkAutoTUnref<SkShader> fShader;
89 SkAutoTUnref<SkSurface> fMinSurface;
90 SkAutoTUnref<SkSurface> fMaxSurface;
91
92 void setupPaint(SkPaint* paint) {
93 bool aa = this->getAA();
94 switch (fStyle) {
95 case kHair_Style:
96 paint->setStrokeWidth(0);
97 break;
98 case kStroke_Style:
99 paint->setStrokeWidth(SK_Scalar1 + SK_Scalar1/500);
100 break;
101 }
102 paint->setAntiAlias(aa);
103 }
104
105 void drawLineSkeleton(SkCanvas* max, const SkPoint pts[]);
106 void drawRectSkeleton(SkCanvas* max, const SkRect& r) {
107 SkPaint paint;
108 paint.setStyle(SkPaint::kStroke_Style);
109 paint.setColor(SK_ColorRED);
110 paint.setAntiAlias(true);
111 max->drawRect(r, paint);
112 }
113
114 void copyMinToMax() {
115 erase(fMaxSurface);
116 SkCanvas* canvas = fMaxSurface->getCanvas();
117 canvas->save();
118 canvas->concat(fMatrix);
119 fMinSurface->draw(canvas, 0, 0, NULL);
120 canvas->restore();
121
122 SkPaint paint;
123 paint.setXfermodeMode(SkXfermode::kClear_Mode);
124 for (int iy = 1; iy < fH; ++iy) {
125 SkScalar y = SkIntToScalar(iy * fZ);
126 canvas->drawLine(0, y - SK_ScalarHalf, 999, y - SK_ScalarHalf, paint);
127 }
128 for (int ix = 1; ix < fW; ++ix) {
129 SkScalar x = SkIntToScalar(ix * fZ);
130 canvas->drawLine(x - SK_ScalarHalf, 0, x - SK_ScalarHalf, 999, paint);
131 }
132 }
133};
134
135void FatBits::drawBG(SkCanvas* canvas) {
136 SkPaint paint;
137
138 paint.setShader(fShader);
139 canvas->drawRect(fBounds, paint);
140 paint.setShader(NULL);
141}
142
143void FatBits::drawFG(SkCanvas* canvas) {
144 SkPaint paint;
145 paint.setAntiAlias(true);
146 paint.setColor(0xFFFFAA66);
147 paint.setStrokeWidth(SK_Scalar1 * 2);
148
149 SkScalar half = SkIntToScalar(fZ) / 2;
150 for (int iy = 0; iy < fH; ++iy) {
151 SkScalar y = SkIntToScalar(iy * fZ) + half;
152 for (int ix = 0; ix < fW; ++ix) {
153 SkScalar x = SkIntToScalar(ix * fZ) + half;
154
155 canvas->drawPoint(x, y, paint);
156 }
157 }
158}
159
160void FatBits::drawLineSkeleton(SkCanvas* max, const SkPoint pts[]) {
161 SkPaint paint;
162 paint.setStyle(SkPaint::kStroke_Style);
163 paint.setColor(SK_ColorRED);
164 paint.setAntiAlias(true);
165
166 SkPath path;
167 path.moveTo(pts[0]);
168 path.lineTo(pts[1]);
169
170 switch (fStyle) {
171 case kHair_Style:
172 break;
173 case kStroke_Style: {
174 SkPaint p;
175 p.setStyle(SkPaint::kStroke_Style);
176 p.setStrokeWidth(SK_Scalar1 * fZ);
177 SkPath dst;
178 p.getFillPath(path, &dst);
179 path = dst;
180 } break;
181 }
182 max->drawPath(path, paint);
183}
184
185void FatBits::drawLine(SkCanvas* canvas, SkPoint pts[]) {
186 SkPaint paint;
187
188 fInverse.mapPoints(pts, 2);
189
190 if (fGrid) {
191 pts[0].set(SkScalarRoundToScalar(pts[0].fX), SkScalarRoundToScalar(pts[0].fY));
192 pts[1].set(SkScalarRoundToScalar(pts[1].fX), SkScalarRoundToScalar(pts[1].fY));
193 }
194
195 erase(fMinSurface);
196 this->setupPaint(&paint);
197 paint.setColor(SK_ColorBLUE);
198 fMinSurface->getCanvas()->drawLine(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, paint);
199 this->copyMinToMax();
200
201 SkCanvas* max = fMaxSurface->getCanvas();
202
203 fMatrix.mapPoints(pts, 2);
204 this->drawLineSkeleton(max, pts);
205
206 fMaxSurface->draw(canvas, 0, 0, NULL);
207}
208
209void FatBits::drawRect(SkCanvas* canvas, SkPoint pts[2]) {
210 SkPaint paint;
211
212 fInverse.mapPoints(pts, 2);
213
214 if (fGrid) {
215 pts[0].set(SkScalarRoundToScalar(pts[0].fX), SkScalarRoundToScalar(pts[0].fY));
216 pts[1].set(SkScalarRoundToScalar(pts[1].fX), SkScalarRoundToScalar(pts[1].fY));
217 }
218
219 SkRect r;
220 r.set(pts, 2);
221
222 erase(fMinSurface);
223 this->setupPaint(&paint);
224 paint.setColor(SK_ColorBLUE);
225 fMinSurface->getCanvas()->drawRect(r, paint);
226 this->copyMinToMax();
227
228 SkCanvas* max = fMaxSurface->getCanvas();
229
230 fMatrix.mapPoints(pts, 2);
231 r.set(pts, 2);
232 this->drawRectSkeleton(max, r);
233
234 fMaxSurface->draw(canvas, 0, 0, NULL);
235}
236
237///////////////////////////////////////////////////////////////////////////////////////////////////
238
239class IndexClick : public SkView::Click {
240 int fIndex;
241public:
242 IndexClick(SkView* v, int index) : SkView::Click(v), fIndex(index) {}
243
244 static int GetIndex(SkView::Click* click) {
245 return ((IndexClick*)click)->fIndex;
246 }
247};
248
249class DrawLineView : public SampleView {
250 FatBits fFB;
251 SkPoint fPts[2];
252 bool fIsRect;
253public:
254 DrawLineView() {
255 fFB.setWHZ(24, 16, 48);
256 fPts[0].set(32, 32);
257 fPts[1].set(32 * 5, 32 * 4);
258 fIsRect = true;
259 }
260
261 void setStyle(FatBits::Style s) {
262 fFB.setStyle(s);
263 this->inval(NULL);
264 }
265
266protected:
267 virtual bool onQuery(SkEvent* evt) SK_OVERRIDE {
268 if (SampleCode::TitleQ(*evt)) {
269 SampleCode::TitleR(evt, "FatBits");
270 return true;
271 }
272 SkUnichar uni;
273 if (SampleCode::CharQ(*evt, &uni)) {
274 switch (uni) {
275 case 'r':
276 fIsRect = !fIsRect;
277 this->inval(NULL);
278 return true;
279 case 'g':
280 fFB.setGrid(!fFB.getGrid());
281 this->inval(NULL);
282 return true;
283 case 's':
284 if (FatBits::kStroke_Style == fFB.getStyle()) {
285 this->setStyle(FatBits::kHair_Style);
286 } else {
287 this->setStyle(FatBits::kStroke_Style);
288 }
289 return true;
290 case 'a':
291 fFB.setAA(!fFB.getAA());
292 this->inval(NULL);
293 return true;
294 }
295 }
296 return this->INHERITED::onQuery(evt);
297 }
298
299 virtual void onDrawContent(SkCanvas* canvas) {
300 fFB.drawBG(canvas);
301 if (fIsRect) {
302 fFB.drawRect(canvas, fPts);
303 } else {
304 fFB.drawLine(canvas, fPts);
305 }
306 fFB.drawFG(canvas);
307 }
308
309 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
310 SkPoint pt = { x, y };
311 int index = -1;
312 SkScalar tol = 8;
313 if (fPts[0].equalsWithinTolerance(pt, tol)) {
314 index = 0;
315 } else if (fPts[1].equalsWithinTolerance(pt, tol)) {
316 index = 1;
317 }
318 return index >= 0 ? new IndexClick(this, index) : NULL;
319 }
320
321 virtual bool onClick(Click* click) {
322 int index = IndexClick::GetIndex(click);
323 SkASSERT(index >= 0 && index <= 1);
324 fPts[index] = click->fCurr;
325 this->inval(NULL);
326 return true;
327 }
328
329private:
330
331 typedef SampleView INHERITED;
332};
333
334//////////////////////////////////////////////////////////////////////////////
335
336static SkView* MyFactory() { return new DrawLineView; }
337static SkViewRegister reg(MyFactory);
338