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