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