2 * Copyright 2012 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "sk_tool_utils.h"
9 #include "SampleCode.h"
17 #include "SkSurface.h"
19 #define FAT_PIXEL_COLOR SK_ColorBLACK
20 #define PIXEL_CENTER_SIZE 3
21 #define WIRE_FRAME_COLOR 0xFFFF0000 /*0xFF00FFFF*/
22 #define WIRE_FRAME_SIZE 1.5f
24 static SkScalar apply_grid(SkScalar x) {
25 const SkScalar grid = 2;
26 return SkScalarRoundToScalar(x * grid) / grid;
29 static void apply_grid(SkPoint pts[], int count) {
30 for (int i = 0; i < count; ++i) {
31 pts[i].set(apply_grid(pts[i].fX), apply_grid(pts[i].fY));
35 static void erase(SkSurface* surface) {
36 surface->getCanvas()->clear(SK_ColorTRANSPARENT);
49 fStrokeCap = SkPaint::kButt_Cap;
51 fClipRect.set(2, 2, 11, 8 );
54 int getZoom() const { return fZoom; }
56 bool getAA() const { return fAA; }
57 void setAA(bool aa) { fAA = aa; }
59 bool getGrid() const { return fGrid; }
60 void setGrid(bool g) { fGrid = g; }
62 bool getShowSkeleton() const { return fShowSkeleton; }
63 void setShowSkeleton(bool ss) { fShowSkeleton = ss; }
65 bool getTriangle() const { return fUseTriangle; }
66 void setTriangle(bool ut) { fUseTriangle = ut; }
68 void toggleRectAsOval() { fRectAsOval = !fRectAsOval; }
70 void togglePixelColors() {
71 if (fShader == fShader0) {
78 bool getUseClip() const { return fUseClip; }
79 void setUseClip(bool uc) { fUseClip = uc; }
85 Style getStyle() const { return fStyle; }
86 void setStyle(Style s) { fStyle = s; }
88 void setWHZ(int width, int height, int zoom) {
92 fBounds.set(0, 0, SkIntToScalar(width * zoom), SkIntToScalar(height * zoom));
93 fMatrix.setScale(SkIntToScalar(zoom), SkIntToScalar(zoom));
94 fInverse.setScale(SK_Scalar1 / zoom, SK_Scalar1 / zoom);
95 fShader0 = sk_tool_utils::create_checkerboard_shader(0xFFDDDDDD, 0xFFFFFFFF, zoom);
96 fShader1 = SkShader::MakeColorShader(SK_ColorWHITE);
99 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
100 fMinSurface = SkSurface::MakeRaster(info);
101 info = info.makeWH(width * zoom, height * zoom);
102 fMaxSurface = SkSurface::MakeRaster(info);
105 void drawBG(SkCanvas*);
106 void drawFG(SkCanvas*);
107 void drawLine(SkCanvas*, SkPoint pts[2]);
108 void drawRect(SkCanvas* canvas, SkPoint pts[2]);
109 void drawTriangle(SkCanvas* canvas, SkPoint pts[3]);
111 SkPaint::Cap fStrokeCap;
114 bool fAA, fGrid, fShowSkeleton, fUseClip, fRectAsOval, fUseTriangle;
117 SkMatrix fMatrix, fInverse;
118 SkRect fBounds, fClipRect;
119 sk_sp<SkShader> fShader0;
120 sk_sp<SkShader> fShader1;
121 sk_sp<SkShader> fShader;
122 sk_sp<SkSurface> fMinSurface;
123 sk_sp<SkSurface> fMaxSurface;
125 void setupPaint(SkPaint* paint) {
126 bool aa = this->getAA();
127 paint->setStrokeCap(fStrokeCap);
130 paint->setStrokeWidth(0);
133 paint->setStrokeWidth(SK_Scalar1);
136 paint->setAntiAlias(aa);
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);
146 void drawTriangleSkeleton(SkCanvas* max, const SkPoint pts[]);
147 void drawLineSkeleton(SkCanvas* max, const SkPoint pts[]);
148 void drawRectSkeleton(SkCanvas* max, const SkRect& r) {
150 this->setupSkeletonPaint(&paint);
153 fRectAsOval ? path.addOval(r) : path.addRect(r);
154 max->drawPath(path, paint);
157 void copyMinToMax() {
158 erase(fMaxSurface.get());
159 SkCanvas* canvas = fMaxSurface->getCanvas();
161 canvas->concat(fMatrix);
162 fMinSurface->draw(canvas, 0, 0, nullptr);
166 paint.setBlendMode(SkBlendMode::kClear);
167 for (int iy = 1; iy < fH; ++iy) {
168 SkScalar y = SkIntToScalar(iy * fZoom);
169 canvas->drawLine(0, y - SK_ScalarHalf, 999, y - SK_ScalarHalf, paint);
171 for (int ix = 1; ix < fW; ++ix) {
172 SkScalar x = SkIntToScalar(ix * fZoom);
173 canvas->drawLine(x - SK_ScalarHalf, 0, x - SK_ScalarHalf, 999, paint);
178 void FatBits::drawBG(SkCanvas* canvas) {
181 paint.setShader(fShader);
182 canvas->drawRect(fBounds, paint);
183 paint.setShader(nullptr);
186 void FatBits::drawFG(SkCanvas* canvas) {
187 SkPaint inner, outer;
189 inner.setAntiAlias(true);
190 inner.setColor(SK_ColorBLACK);
191 inner.setStrokeWidth(PIXEL_CENTER_SIZE);
193 outer.setAntiAlias(true);
194 outer.setColor(SK_ColorWHITE);
195 outer.setStrokeWidth(PIXEL_CENTER_SIZE + 2);
197 SkScalar half = SkIntToScalar(fZoom) / 2;
198 for (int iy = 0; iy < fH; ++iy) {
199 SkScalar y = SkIntToScalar(iy * fZoom) + half;
200 for (int ix = 0; ix < fW; ++ix) {
201 SkScalar x = SkIntToScalar(ix * fZoom) + half;
203 canvas->drawPoint(x, y, outer);
204 canvas->drawPoint(x, y, inner);
210 p.setStyle(SkPaint::kStroke_Style);
211 p.setColor(SK_ColorLTGRAY);
213 fClipRect.fLeft * fZoom,
214 fClipRect.fTop * fZoom,
215 fClipRect.fRight * fZoom,
216 fClipRect.fBottom * fZoom
218 canvas->drawRect(r, p);
222 void FatBits::drawLineSkeleton(SkCanvas* max, const SkPoint pts[]) {
224 this->setupSkeletonPaint(&paint);
230 if (fStyle == kStroke_Style) {
232 p.setStyle(SkPaint::kStroke_Style);
233 p.setStrokeWidth(SK_Scalar1 * fZoom);
234 p.setStrokeCap(fStrokeCap);
236 p.getFillPath(path, &dst);
242 max->drawPath(path, paint);
245 void FatBits::drawLine(SkCanvas* canvas, SkPoint pts[]) {
248 fInverse.mapPoints(pts, 2);
254 erase(fMinSurface.get());
255 this->setupPaint(&paint);
256 paint.setColor(FAT_PIXEL_COLOR);
258 fMinSurface->getCanvas()->save();
259 SkRect r = fClipRect;
260 r.inset(SK_Scalar1/3, SK_Scalar1/3);
261 fMinSurface->getCanvas()->clipRect(r, SkCanvas::kIntersect_Op, true);
263 fMinSurface->getCanvas()->drawLine(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, paint);
265 fMinSurface->getCanvas()->restore();
267 this->copyMinToMax();
269 SkCanvas* max = fMaxSurface->getCanvas();
271 fMatrix.mapPoints(pts, 2);
272 this->drawLineSkeleton(max, pts);
274 fMaxSurface->draw(canvas, 0, 0, nullptr);
277 void FatBits::drawRect(SkCanvas* canvas, SkPoint pts[2]) {
280 fInverse.mapPoints(pts, 2);
289 erase(fMinSurface.get());
290 this->setupPaint(&paint);
291 paint.setColor(FAT_PIXEL_COLOR);
293 SkCanvas* c = fMinSurface->getCanvas();
294 fRectAsOval ? c->drawOval(r, paint) : c->drawRect(r, paint);
296 this->copyMinToMax();
298 SkCanvas* max = fMaxSurface->getCanvas();
300 fMatrix.mapPoints(pts, 2);
302 this->drawRectSkeleton(max, r);
304 fMaxSurface->draw(canvas, 0, 0, nullptr);
307 void FatBits::drawTriangleSkeleton(SkCanvas* max, const SkPoint pts[]) {
309 this->setupSkeletonPaint(&paint);
317 max->drawPath(path, paint);
320 void FatBits::drawTriangle(SkCanvas* canvas, SkPoint pts[3]) {
323 fInverse.mapPoints(pts, 3);
335 erase(fMinSurface.get());
336 this->setupPaint(&paint);
337 paint.setColor(FAT_PIXEL_COLOR);
338 fMinSurface->getCanvas()->drawPath(path, paint);
339 this->copyMinToMax();
341 SkCanvas* max = fMaxSurface->getCanvas();
343 fMatrix.mapPoints(pts, 3);
344 this->drawTriangleSkeleton(max, pts);
346 fMaxSurface->draw(canvas, 0, 0, nullptr);
349 ///////////////////////////////////////////////////////////////////////////////////////////////////
351 class IndexClick : public SkView::Click {
354 IndexClick(SkView* v, int index) : SkView::Click(v), fIndex(index) {}
356 static int GetIndex(SkView::Click* click) {
357 return ((IndexClick*)click)->fIndex;
361 class DrawLineView : public SampleView {
368 fFB.setWHZ(24*2, 16*2, fZoom);
372 SkMatrix::MakeScale(SkIntToScalar(fZoom)).mapPoints(fPts, 3);
376 void setStyle(FatBits::Style s) {
378 this->inval(nullptr);
382 bool onQuery(SkEvent* evt) override {
383 if (SampleCode::TitleQ(*evt)) {
384 SampleCode::TitleR(evt, "FatBits");
388 if (SampleCode::CharQ(*evt, &uni)) {
391 fFB.setUseClip(!fFB.getUseClip());
392 this->inval(nullptr);
396 this->inval(nullptr);
399 fFB.toggleRectAsOval();
400 this->inval(nullptr);
403 fFB.setGrid(!fFB.getGrid());
404 this->inval(nullptr);
407 if (FatBits::kStroke_Style == fFB.getStyle()) {
408 this->setStyle(FatBits::kHair_Style);
410 this->setStyle(FatBits::kStroke_Style);
414 const SkPaint::Cap caps[] = {
415 SkPaint::kButt_Cap, SkPaint::kRound_Cap, SkPaint::kSquare_Cap,
417 fFB.fStrokeCap = caps[(fFB.fStrokeCap + 1) % 3];
418 this->inval(nullptr);
422 fFB.setAA(!fFB.getAA());
423 this->inval(nullptr);
426 fFB.setShowSkeleton(!fFB.getShowSkeleton());
427 this->inval(nullptr);
430 fFB.togglePixelColors();
431 this->inval(nullptr);
434 fFB.setTriangle(!fFB.getTriangle());
435 this->inval(nullptr);
439 return this->INHERITED::onQuery(evt);
442 void onDrawContent(SkCanvas* canvas) override {
444 if (fFB.getTriangle()) {
445 fFB.drawTriangle(canvas, fPts);
448 fFB.drawRect(canvas, fPts);
450 fFB.drawLine(canvas, fPts);
456 str.printf("%s %s %s",
457 fFB.getAA() ? "AA" : "BW",
458 FatBits::kHair_Style == fFB.getStyle() ? "Hair" : "Stroke",
459 fFB.getUseClip() ? "clip" : "noclip");
461 paint.setAntiAlias(true);
462 paint.setTextSize(16);
463 paint.setColor(SK_ColorBLUE);
464 canvas->drawText(str.c_str(), str.size(), 10, 16, paint);
468 SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override {
469 SkPoint pt = { x, y };
471 int count = fFB.getTriangle() ? 3 : 2;
474 for (int i = 0; i < count; ++i) {
475 if (fPts[i].equalsWithinTolerance(pt, tol)) {
480 return new IndexClick(this, index);
483 bool onClick(Click* click) override {
484 int index = IndexClick::GetIndex(click);
485 if (index >= 0 && index <= 2) {
486 fPts[index] = click->fCurr;
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);
494 this->inval(nullptr);
500 typedef SampleView INHERITED;
503 //////////////////////////////////////////////////////////////////////////////
505 static SkView* MyFactory() { return new DrawLineView; }
506 static SkViewRegister reg(MyFactory);