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