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