• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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