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