1 /*
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
18 #define FAT_PIXEL_COLOR SK_ColorBLACK
19 #define PIXEL_CENTER_SIZE 3
20 #define WIRE_FRAME_COLOR 0xFFFF0000 /*0xFF00FFFF*/
21 #define WIRE_FRAME_SIZE 1.5f
22
apply_grid(SkScalar x)23 static SkScalar apply_grid(SkScalar x) {
24 const SkScalar grid = 2;
25 return SkScalarRoundToScalar(x * grid) / grid;
26 }
27
apply_grid(SkPoint pts[],int count)28 static void apply_grid(SkPoint pts[], int count) {
29 for (int i = 0; i < count; ++i) {
30 pts[i].set(apply_grid(pts[i].fX), apply_grid(pts[i].fY));
31 }
32 }
33
erase(SkSurface * surface)34 static void erase(SkSurface* surface) {
35 surface->getCanvas()->clear(SK_ColorTRANSPARENT);
36 }
37
createChecker(const SkMatrix & localMatrix)38 static SkShader* createChecker(const SkMatrix& localMatrix) {
39 // SkColor colors[] = { 0xFFFDFDFD, 0xFFF4F4F4 };
40 SkColor colors[] = { 0xFFFFFFFF, 0xFFFFFFFF };
41 SkBitmap bm;
42 bm.allocN32Pixels(2, 2);
43 bm.lockPixels();
44 *bm.getAddr32(0, 0) = *bm.getAddr32(1, 1) = SkPreMultiplyColor(colors[0]);
45 *bm.getAddr32(0, 1) = *bm.getAddr32(1, 0) = SkPreMultiplyColor(colors[1]);
46 return SkShader::CreateBitmapShader(bm, SkShader::kRepeat_TileMode,
47 SkShader::kRepeat_TileMode, &localMatrix);
48 }
49
50 class FatBits {
51 public:
FatBits()52 FatBits() {
53 fAA = false;
54 fStyle = kHair_Style;
55 fGrid = true;
56 fShowSkeleton = true;
57 fUseGPU = false;
58 fUseClip = false;
59 fRectAsOval = false;
60 fUseTriangle = false;
61
62 fClipRect.set(2, 2, 11, 8 );
63 }
64
getZoom() const65 int getZoom() const { return fZoom; }
66
getAA() const67 bool getAA() const { return fAA; }
setAA(bool aa)68 void setAA(bool aa) { fAA = aa; }
69
getGrid() const70 bool getGrid() const { return fGrid; }
setGrid(bool g)71 void setGrid(bool g) { fGrid = g; }
72
getShowSkeleton() const73 bool getShowSkeleton() const { return fShowSkeleton; }
setShowSkeleton(bool ss)74 void setShowSkeleton(bool ss) { fShowSkeleton = ss; }
75
getUseGPU() const76 bool getUseGPU() const { return fUseGPU; }
setUseGPU(bool ug)77 void setUseGPU(bool ug) { fUseGPU = ug; }
78
getTriangle() const79 bool getTriangle() const { return fUseTriangle; }
setTriangle(bool ut)80 void setTriangle(bool ut) { fUseTriangle = ut; }
81
toggleRectAsOval()82 void toggleRectAsOval() { fRectAsOval = !fRectAsOval; }
83
getUseClip() const84 bool getUseClip() const { return fUseClip; }
setUseClip(bool uc)85 void setUseClip(bool uc) { fUseClip = uc; }
86
87 enum Style {
88 kHair_Style,
89 kStroke_Style,
90 };
getStyle() const91 Style getStyle() const { return fStyle; }
setStyle(Style s)92 void setStyle(Style s) { fStyle = s; }
93
setWHZ(int width,int height,int zoom)94 void setWHZ(int width, int height, int zoom) {
95 fW = width;
96 fH = height;
97 fZoom = zoom;
98 fBounds.set(0, 0, SkIntToScalar(width * zoom), SkIntToScalar(height * zoom));
99 fMatrix.setScale(SkIntToScalar(zoom), SkIntToScalar(zoom));
100 fInverse.setScale(SK_Scalar1 / zoom, SK_Scalar1 / zoom);
101 fShader.reset(createChecker(fMatrix));
102
103 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
104 fMinSurface.reset(SkSurface::NewRaster(info));
105 info.fWidth *= zoom;
106 info.fHeight *= zoom;
107 fMaxSurface.reset(SkSurface::NewRaster(info));
108 }
109
110 void drawBG(SkCanvas*);
111 void drawFG(SkCanvas*);
112 void drawLine(SkCanvas*, SkPoint pts[2]);
113 void drawRect(SkCanvas* canvas, SkPoint pts[2]);
114 void drawTriangle(SkCanvas* canvas, SkPoint pts[3]);
115
116 private:
117 bool fAA, fGrid, fShowSkeleton, fUseGPU, fUseClip, fRectAsOval, fUseTriangle;
118 Style fStyle;
119 int fW, fH, fZoom;
120 SkMatrix fMatrix, fInverse;
121 SkRect fBounds, fClipRect;
122 SkAutoTUnref<SkShader> fShader;
123 SkAutoTUnref<SkSurface> fMinSurface;
124 SkAutoTUnref<SkSurface> fMaxSurface;
125
setupPaint(SkPaint * paint)126 void setupPaint(SkPaint* paint) {
127 bool aa = this->getAA();
128 switch (fStyle) {
129 case kHair_Style:
130 paint->setStrokeWidth(0);
131 break;
132 case kStroke_Style:
133 paint->setStrokeWidth(SK_Scalar1);
134 break;
135 }
136 paint->setAntiAlias(aa);
137 }
138
setupSkeletonPaint(SkPaint * paint)139 void setupSkeletonPaint(SkPaint* paint) {
140 paint->setStyle(SkPaint::kStroke_Style);
141 paint->setStrokeWidth(WIRE_FRAME_SIZE);
142 paint->setColor(fShowSkeleton ? WIRE_FRAME_COLOR : 0);
143 paint->setAntiAlias(true);
144 }
145
146 void drawTriangleSkeleton(SkCanvas* max, const SkPoint pts[]);
147 void drawLineSkeleton(SkCanvas* max, const SkPoint pts[]);
drawRectSkeleton(SkCanvas * max,const SkRect & r)148 void drawRectSkeleton(SkCanvas* max, const SkRect& r) {
149 SkPaint paint;
150 this->setupSkeletonPaint(&paint);
151 SkPath path;
152
153 if (fUseGPU && fAA) {
154 SkRect rr = r;
155 rr.inset(SkIntToScalar(fZoom)/2, SkIntToScalar(fZoom)/2);
156 path.addRect(rr);
157 path.moveTo(rr.fLeft, rr.fTop);
158 path.lineTo(rr.fRight, rr.fBottom);
159 rr = r;
160 rr.inset(-SkIntToScalar(fZoom)/2, -SkIntToScalar(fZoom)/2);
161 path.addRect(rr);
162 } else {
163 fRectAsOval ? path.addOval(r) : path.addRect(r);
164 if (fUseGPU) {
165 path.moveTo(r.fLeft, r.fTop);
166 path.lineTo(r.fRight, r.fBottom);
167 }
168 }
169 max->drawPath(path, paint);
170 }
171
copyMinToMax()172 void copyMinToMax() {
173 erase(fMaxSurface);
174 SkCanvas* canvas = fMaxSurface->getCanvas();
175 canvas->save();
176 canvas->concat(fMatrix);
177 fMinSurface->draw(canvas, 0, 0, NULL);
178 canvas->restore();
179
180 SkPaint paint;
181 paint.setXfermodeMode(SkXfermode::kClear_Mode);
182 for (int iy = 1; iy < fH; ++iy) {
183 SkScalar y = SkIntToScalar(iy * fZoom);
184 canvas->drawLine(0, y - SK_ScalarHalf, 999, y - SK_ScalarHalf, paint);
185 }
186 for (int ix = 1; ix < fW; ++ix) {
187 SkScalar x = SkIntToScalar(ix * fZoom);
188 canvas->drawLine(x - SK_ScalarHalf, 0, x - SK_ScalarHalf, 999, paint);
189 }
190 }
191 };
192
drawBG(SkCanvas * canvas)193 void FatBits::drawBG(SkCanvas* canvas) {
194 SkPaint paint;
195
196 paint.setShader(fShader);
197 canvas->drawRect(fBounds, paint);
198 paint.setShader(NULL);
199 }
200
drawFG(SkCanvas * canvas)201 void FatBits::drawFG(SkCanvas* canvas) {
202 SkPaint inner, outer;
203
204 inner.setAntiAlias(true);
205 inner.setColor(SK_ColorBLACK);
206 inner.setStrokeWidth(PIXEL_CENTER_SIZE);
207
208 outer.setAntiAlias(true);
209 outer.setColor(SK_ColorWHITE);
210 outer.setStrokeWidth(PIXEL_CENTER_SIZE + 2);
211
212 SkScalar half = SkIntToScalar(fZoom) / 2;
213 for (int iy = 0; iy < fH; ++iy) {
214 SkScalar y = SkIntToScalar(iy * fZoom) + half;
215 for (int ix = 0; ix < fW; ++ix) {
216 SkScalar x = SkIntToScalar(ix * fZoom) + half;
217
218 canvas->drawPoint(x, y, outer);
219 canvas->drawPoint(x, y, inner);
220 }
221 }
222
223 if (fUseClip) {
224 SkPaint p;
225 p.setStyle(SkPaint::kStroke_Style);
226 p.setColor(SK_ColorLTGRAY);
227 SkRect r = {
228 fClipRect.fLeft * fZoom,
229 fClipRect.fTop * fZoom,
230 fClipRect.fRight * fZoom,
231 fClipRect.fBottom * fZoom
232 };
233 canvas->drawRect(r, p);
234 }
235 }
236
drawLineSkeleton(SkCanvas * max,const SkPoint pts[])237 void FatBits::drawLineSkeleton(SkCanvas* max, const SkPoint pts[]) {
238 SkPaint paint;
239 this->setupSkeletonPaint(&paint);
240
241 SkPath path;
242 path.moveTo(pts[0]);
243 path.lineTo(pts[1]);
244
245 switch (fStyle) {
246 case kHair_Style:
247 if (fUseGPU) {
248 SkPaint p;
249 p.setStyle(SkPaint::kStroke_Style);
250 p.setStrokeWidth(SK_Scalar1 * fZoom);
251 SkPath dst;
252 p.getFillPath(path, &dst);
253 path.addPath(dst);
254 }
255 break;
256 case kStroke_Style: {
257 SkPaint p;
258 p.setStyle(SkPaint::kStroke_Style);
259 p.setStrokeWidth(SK_Scalar1 * fZoom);
260 SkPath dst;
261 p.getFillPath(path, &dst);
262 path = dst;
263
264 if (fUseGPU) {
265 path.moveTo(dst.getPoint(0));
266 path.lineTo(dst.getPoint(2));
267 }
268 } break;
269 }
270 max->drawPath(path, paint);
271 }
272
drawLine(SkCanvas * canvas,SkPoint pts[])273 void FatBits::drawLine(SkCanvas* canvas, SkPoint pts[]) {
274 SkPaint paint;
275
276 fInverse.mapPoints(pts, 2);
277
278 if (fGrid) {
279 apply_grid(pts, 2);
280 }
281
282 erase(fMinSurface);
283 this->setupPaint(&paint);
284 paint.setColor(FAT_PIXEL_COLOR);
285 if (fUseClip) {
286 fMinSurface->getCanvas()->save();
287 SkRect r = fClipRect;
288 r.inset(SK_Scalar1/3, SK_Scalar1/3);
289 fMinSurface->getCanvas()->clipRect(r, SkRegion::kIntersect_Op, true);
290 }
291 fMinSurface->getCanvas()->drawLine(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, paint);
292 if (fUseClip) {
293 fMinSurface->getCanvas()->restore();
294 }
295 this->copyMinToMax();
296
297 SkCanvas* max = fMaxSurface->getCanvas();
298
299 fMatrix.mapPoints(pts, 2);
300 this->drawLineSkeleton(max, pts);
301
302 fMaxSurface->draw(canvas, 0, 0, NULL);
303 }
304
drawRect(SkCanvas * canvas,SkPoint pts[2])305 void FatBits::drawRect(SkCanvas* canvas, SkPoint pts[2]) {
306 SkPaint paint;
307
308 fInverse.mapPoints(pts, 2);
309
310 if (fGrid) {
311 apply_grid(pts, 2);
312 }
313
314 SkRect r;
315 r.set(pts, 2);
316
317 erase(fMinSurface);
318 this->setupPaint(&paint);
319 paint.setColor(FAT_PIXEL_COLOR);
320 {
321 SkCanvas* c = fMinSurface->getCanvas();
322 fRectAsOval ? c->drawOval(r, paint) : c->drawRect(r, paint);
323 }
324 this->copyMinToMax();
325
326 SkCanvas* max = fMaxSurface->getCanvas();
327
328 fMatrix.mapPoints(pts, 2);
329 r.set(pts, 2);
330 this->drawRectSkeleton(max, r);
331
332 fMaxSurface->draw(canvas, 0, 0, NULL);
333 }
334
drawTriangleSkeleton(SkCanvas * max,const SkPoint pts[])335 void FatBits::drawTriangleSkeleton(SkCanvas* max, const SkPoint pts[]) {
336 SkPaint paint;
337 this->setupSkeletonPaint(&paint);
338
339 SkPath path;
340 path.moveTo(pts[0]);
341 path.lineTo(pts[1]);
342 path.lineTo(pts[2]);
343 path.close();
344
345 max->drawPath(path, paint);
346 }
347
drawTriangle(SkCanvas * canvas,SkPoint pts[3])348 void FatBits::drawTriangle(SkCanvas* canvas, SkPoint pts[3]) {
349 SkPaint paint;
350
351 fInverse.mapPoints(pts, 3);
352
353 if (fGrid) {
354 apply_grid(pts, 3);
355 }
356
357 SkPath path;
358 path.moveTo(pts[0]);
359 path.lineTo(pts[1]);
360 path.lineTo(pts[2]);
361 path.close();
362
363 erase(fMinSurface);
364 this->setupPaint(&paint);
365 paint.setColor(FAT_PIXEL_COLOR);
366 fMinSurface->getCanvas()->drawPath(path, paint);
367 this->copyMinToMax();
368
369 SkCanvas* max = fMaxSurface->getCanvas();
370
371 fMatrix.mapPoints(pts, 3);
372 this->drawTriangleSkeleton(max, pts);
373
374 fMaxSurface->draw(canvas, 0, 0, NULL);
375 }
376
377 ///////////////////////////////////////////////////////////////////////////////////////////////////
378
379 class IndexClick : public SkView::Click {
380 int fIndex;
381 public:
IndexClick(SkView * v,int index)382 IndexClick(SkView* v, int index) : SkView::Click(v), fIndex(index) {}
383
GetIndex(SkView::Click * click)384 static int GetIndex(SkView::Click* click) {
385 return ((IndexClick*)click)->fIndex;
386 }
387 };
388
389 class DrawLineView : public SampleView {
390 FatBits fFB;
391 SkPoint fPts[3];
392 bool fIsRect;
393 public:
DrawLineView()394 DrawLineView() {
395 fFB.setWHZ(24, 16, 48);
396 fPts[0].set(48, 48);
397 fPts[1].set(48 * 5, 48 * 4);
398 fPts[2].set(48 * 2, 48 * 6);
399 fIsRect = false;
400 }
401
setStyle(FatBits::Style s)402 void setStyle(FatBits::Style s) {
403 fFB.setStyle(s);
404 this->inval(NULL);
405 }
406
407 protected:
onQuery(SkEvent * evt)408 virtual bool onQuery(SkEvent* evt) SK_OVERRIDE {
409 if (SampleCode::TitleQ(*evt)) {
410 SampleCode::TitleR(evt, "FatBits");
411 return true;
412 }
413 SkUnichar uni;
414 if (SampleCode::CharQ(*evt, &uni)) {
415 switch (uni) {
416 case 'c':
417 fFB.setUseClip(!fFB.getUseClip());
418 this->inval(NULL);
419 return true;
420 case 'r':
421 fIsRect = !fIsRect;
422 this->inval(NULL);
423 return true;
424 case 'o':
425 fFB.toggleRectAsOval();
426 this->inval(NULL);
427 return true;
428 case 'x':
429 fFB.setGrid(!fFB.getGrid());
430 this->inval(NULL);
431 return true;
432 case 's':
433 if (FatBits::kStroke_Style == fFB.getStyle()) {
434 this->setStyle(FatBits::kHair_Style);
435 } else {
436 this->setStyle(FatBits::kStroke_Style);
437 }
438 return true;
439 case 'a':
440 fFB.setAA(!fFB.getAA());
441 this->inval(NULL);
442 return true;
443 case 'w':
444 fFB.setShowSkeleton(!fFB.getShowSkeleton());
445 this->inval(NULL);
446 return true;
447 case 'g':
448 fFB.setUseGPU(!fFB.getUseGPU());
449 this->inval(NULL);
450 return true;
451 case 't':
452 fFB.setTriangle(!fFB.getTriangle());
453 this->inval(NULL);
454 return true;
455 }
456 }
457 return this->INHERITED::onQuery(evt);
458 }
459
onDrawContent(SkCanvas * canvas)460 virtual void onDrawContent(SkCanvas* canvas) {
461 fFB.drawBG(canvas);
462 if (fFB.getTriangle()) {
463 fFB.drawTriangle(canvas, fPts);
464 }
465 else if (fIsRect) {
466 fFB.drawRect(canvas, fPts);
467 } else {
468 fFB.drawLine(canvas, fPts);
469 }
470 fFB.drawFG(canvas);
471
472 {
473 SkString str;
474 str.printf("%s %s %s %s",
475 fFB.getAA() ? "AA" : "BW",
476 FatBits::kHair_Style == fFB.getStyle() ? "Hair" : "Stroke",
477 fFB.getUseGPU() ? "GPU" : "CPU",
478 fFB.getUseClip() ? "clip" : "noclip");
479 SkPaint paint;
480 paint.setAntiAlias(true);
481 paint.setTextSize(16);
482 paint.setColor(SK_ColorBLUE);
483 canvas->drawText(str.c_str(), str.size(), 10, 16, paint);
484 }
485 }
486
onFindClickHandler(SkScalar x,SkScalar y,unsigned modi)487 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y,
488 unsigned modi) SK_OVERRIDE {
489 SkPoint pt = { x, y };
490 int index = -1;
491 int count = fFB.getTriangle() ? 3 : 2;
492 SkScalar tol = 12;
493
494 for (int i = 0; i < count; ++i) {
495 if (fPts[i].equalsWithinTolerance(pt, tol)) {
496 index = i;
497 break;
498 }
499 }
500 return new IndexClick(this, index);
501 }
502
onClick(Click * click)503 virtual bool onClick(Click* click) SK_OVERRIDE {
504 int index = IndexClick::GetIndex(click);
505 if (index >= 0 && index <= 2) {
506 fPts[index] = click->fCurr;
507 } else {
508 SkScalar dx = click->fCurr.fX - click->fPrev.fX;
509 SkScalar dy = click->fCurr.fY - click->fPrev.fY;
510 fPts[0].offset(dx, dy);
511 fPts[1].offset(dx, dy);
512 fPts[2].offset(dx, dy);
513 }
514 this->inval(NULL);
515 return true;
516 }
517
518 private:
519
520 typedef SampleView INHERITED;
521 };
522
523 //////////////////////////////////////////////////////////////////////////////
524
MyFactory()525 static SkView* MyFactory() { return new DrawLineView; }
526 static SkViewRegister reg(MyFactory);
527