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