1/* 2 * Copyright 2006 The Android Open Source Project 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 "SkDraw.h" 9#include "SkBlitter.h" 10#include "SkBounder.h" 11#include "SkCanvas.h" 12#include "SkColorPriv.h" 13#include "SkDevice.h" 14#include "SkDeviceLooper.h" 15#include "SkFixed.h" 16#include "SkMaskFilter.h" 17#include "SkPaint.h" 18#include "SkPathEffect.h" 19#include "SkRasterClip.h" 20#include "SkRasterizer.h" 21#include "SkRRect.h" 22#include "SkScan.h" 23#include "SkShader.h" 24#include "SkString.h" 25#include "SkStroke.h" 26#include "SkTemplatesPriv.h" 27#include "SkTLazy.h" 28#include "SkUtils.h" 29 30#include "SkAutoKern.h" 31#include "SkBitmapProcShader.h" 32#include "SkDrawProcs.h" 33#include "SkMatrixUtils.h" 34 35bool SkDraw::ShouldDrawTextAsPaths(const SkPaint& paint, const SkMatrix& ctm) { 36 // we don't cache hairlines in the cache 37 if (SkPaint::kStroke_Style == paint.getStyle() && 38 0 == paint.getStrokeWidth()) { 39 return true; 40 } 41 42 // we don't cache perspective 43 if (ctm.hasPerspective()) { 44 return true; 45 } 46 47 SkMatrix textM; 48 return SkPaint::TooBigToUseCache(ctm, *paint.setTextMatrix(&textM)); 49} 50 51//#define TRACE_BITMAP_DRAWS 52 53#define kBlitterStorageLongCount (sizeof(SkBitmapProcShader) >> 2) 54 55/** Helper for allocating small blitters on the stack. 56 */ 57class SkAutoBlitterChoose : SkNoncopyable { 58public: 59 SkAutoBlitterChoose() { 60 fBlitter = NULL; 61 } 62 SkAutoBlitterChoose(const SkBitmap& device, const SkMatrix& matrix, 63 const SkPaint& paint) { 64 fBlitter = SkBlitter::Choose(device, matrix, paint, 65 fStorage, sizeof(fStorage)); 66 } 67 68 ~SkAutoBlitterChoose(); 69 70 SkBlitter* operator->() { return fBlitter; } 71 SkBlitter* get() const { return fBlitter; } 72 73 void choose(const SkBitmap& device, const SkMatrix& matrix, 74 const SkPaint& paint) { 75 SkASSERT(!fBlitter); 76 fBlitter = SkBlitter::Choose(device, matrix, paint, 77 fStorage, sizeof(fStorage)); 78 } 79 80private: 81 SkBlitter* fBlitter; 82 uint32_t fStorage[kBlitterStorageLongCount]; 83}; 84 85SkAutoBlitterChoose::~SkAutoBlitterChoose() { 86 if ((void*)fBlitter == (void*)fStorage) { 87 fBlitter->~SkBlitter(); 88 } else { 89 SkDELETE(fBlitter); 90 } 91} 92 93/** 94 * Since we are providing the storage for the shader (to avoid the perf cost 95 * of calling new) we insist that in our destructor we can account for all 96 * owners of the shader. 97 */ 98class SkAutoBitmapShaderInstall : SkNoncopyable { 99public: 100 SkAutoBitmapShaderInstall(const SkBitmap& src, const SkPaint& paint) 101 : fPaint(paint) /* makes a copy of the paint */ { 102 fPaint.setShader(SkShader::CreateBitmapShader(src, 103 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, 104 fStorage, sizeof(fStorage))); 105 // we deliberately left the shader with an owner-count of 2 106 SkASSERT(2 == fPaint.getShader()->getRefCnt()); 107 } 108 109 ~SkAutoBitmapShaderInstall() { 110 SkShader* shader = fPaint.getShader(); 111 // since we manually destroy shader, we insist that owners == 2 112 SkASSERT(2 == shader->getRefCnt()); 113 114 fPaint.setShader(NULL); // unref the shader by 1 115 116 // now destroy to take care of the 2nd owner-count 117 if ((void*)shader == (void*)fStorage) { 118 shader->~SkShader(); 119 } else { 120 SkDELETE(shader); 121 } 122 } 123 124 // return the new paint that has the shader applied 125 const SkPaint& paintWithShader() const { return fPaint; } 126 127private: 128 SkPaint fPaint; // copy of caller's paint (which we then modify) 129 uint32_t fStorage[kBlitterStorageLongCount]; 130}; 131 132/////////////////////////////////////////////////////////////////////////////// 133 134SkDraw::SkDraw() { 135 sk_bzero(this, sizeof(*this)); 136} 137 138SkDraw::SkDraw(const SkDraw& src) { 139 memcpy(this, &src, sizeof(*this)); 140} 141 142bool SkDraw::computeConservativeLocalClipBounds(SkRect* localBounds) const { 143 if (fRC->isEmpty()) { 144 return false; 145 } 146 147 SkMatrix inverse; 148 if (!fMatrix->invert(&inverse)) { 149 return false; 150 } 151 152 SkIRect devBounds = fRC->getBounds(); 153 // outset to have slop for antialasing and hairlines 154 devBounds.outset(1, 1); 155 inverse.mapRect(localBounds, SkRect::Make(devBounds)); 156 return true; 157} 158 159/////////////////////////////////////////////////////////////////////////////// 160 161typedef void (*BitmapXferProc)(void* pixels, size_t bytes, uint32_t data); 162 163static void D_Clear_BitmapXferProc(void* pixels, size_t bytes, uint32_t) { 164 sk_bzero(pixels, bytes); 165} 166 167static void D_Dst_BitmapXferProc(void*, size_t, uint32_t data) {} 168 169static void D32_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) { 170 sk_memset32((uint32_t*)pixels, data, bytes >> 2); 171} 172 173static void D16_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) { 174 sk_memset16((uint16_t*)pixels, data, bytes >> 1); 175} 176 177static void DA8_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) { 178 memset(pixels, data, bytes); 179} 180 181static BitmapXferProc ChooseBitmapXferProc(const SkBitmap& bitmap, 182 const SkPaint& paint, 183 uint32_t* data) { 184 // todo: we can apply colorfilter up front if no shader, so we wouldn't 185 // need to abort this fastpath 186 if (paint.getShader() || paint.getColorFilter()) { 187 return NULL; 188 } 189 190 SkXfermode::Mode mode; 191 if (!SkXfermode::AsMode(paint.getXfermode(), &mode)) { 192 return NULL; 193 } 194 195 SkColor color = paint.getColor(); 196 197 // collaps modes based on color... 198 if (SkXfermode::kSrcOver_Mode == mode) { 199 unsigned alpha = SkColorGetA(color); 200 if (0 == alpha) { 201 mode = SkXfermode::kDst_Mode; 202 } else if (0xFF == alpha) { 203 mode = SkXfermode::kSrc_Mode; 204 } 205 } 206 207 switch (mode) { 208 case SkXfermode::kClear_Mode: 209// SkDebugf("--- D_Clear_BitmapXferProc\n"); 210 return D_Clear_BitmapXferProc; // ignore data 211 case SkXfermode::kDst_Mode: 212// SkDebugf("--- D_Dst_BitmapXferProc\n"); 213 return D_Dst_BitmapXferProc; // ignore data 214 case SkXfermode::kSrc_Mode: { 215 /* 216 should I worry about dithering for the lower depths? 217 */ 218 SkPMColor pmc = SkPreMultiplyColor(color); 219 switch (bitmap.config()) { 220 case SkBitmap::kARGB_8888_Config: 221 if (data) { 222 *data = pmc; 223 } 224// SkDebugf("--- D32_Src_BitmapXferProc\n"); 225 return D32_Src_BitmapXferProc; 226 case SkBitmap::kRGB_565_Config: 227 if (data) { 228 *data = SkPixel32ToPixel16(pmc); 229 } 230// SkDebugf("--- D16_Src_BitmapXferProc\n"); 231 return D16_Src_BitmapXferProc; 232 case SkBitmap::kA8_Config: 233 if (data) { 234 *data = SkGetPackedA32(pmc); 235 } 236// SkDebugf("--- DA8_Src_BitmapXferProc\n"); 237 return DA8_Src_BitmapXferProc; 238 default: 239 break; 240 } 241 break; 242 } 243 default: 244 break; 245 } 246 return NULL; 247} 248 249static void CallBitmapXferProc(const SkBitmap& bitmap, const SkIRect& rect, 250 BitmapXferProc proc, uint32_t procData) { 251 int shiftPerPixel; 252 switch (bitmap.config()) { 253 case SkBitmap::kARGB_8888_Config: 254 shiftPerPixel = 2; 255 break; 256 case SkBitmap::kRGB_565_Config: 257 shiftPerPixel = 1; 258 break; 259 case SkBitmap::kA8_Config: 260 shiftPerPixel = 0; 261 break; 262 default: 263 SkDEBUGFAIL("Can't use xferproc on this config"); 264 return; 265 } 266 267 uint8_t* pixels = (uint8_t*)bitmap.getPixels(); 268 SkASSERT(pixels); 269 const size_t rowBytes = bitmap.rowBytes(); 270 const int widthBytes = rect.width() << shiftPerPixel; 271 272 // skip down to the first scanline and X position 273 pixels += rect.fTop * rowBytes + (rect.fLeft << shiftPerPixel); 274 for (int scans = rect.height() - 1; scans >= 0; --scans) { 275 proc(pixels, widthBytes, procData); 276 pixels += rowBytes; 277 } 278} 279 280void SkDraw::drawPaint(const SkPaint& paint) const { 281 SkDEBUGCODE(this->validate();) 282 283 if (fRC->isEmpty()) { 284 return; 285 } 286 287 SkIRect devRect; 288 devRect.set(0, 0, fBitmap->width(), fBitmap->height()); 289 if (fBounder && !fBounder->doIRect(devRect)) { 290 return; 291 } 292 293 if (fRC->isBW()) { 294 /* If we don't have a shader (i.e. we're just a solid color) we may 295 be faster to operate directly on the device bitmap, rather than invoking 296 a blitter. Esp. true for xfermodes, which require a colorshader to be 297 present, which is just redundant work. Since we're drawing everywhere 298 in the clip, we don't have to worry about antialiasing. 299 */ 300 uint32_t procData = 0; // to avoid the warning 301 BitmapXferProc proc = ChooseBitmapXferProc(*fBitmap, paint, &procData); 302 if (proc) { 303 if (D_Dst_BitmapXferProc == proc) { // nothing to do 304 return; 305 } 306 307 SkRegion::Iterator iter(fRC->bwRgn()); 308 while (!iter.done()) { 309 CallBitmapXferProc(*fBitmap, iter.rect(), proc, procData); 310 iter.next(); 311 } 312 return; 313 } 314 } 315 316 // normal case: use a blitter 317 SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint); 318 SkScan::FillIRect(devRect, *fRC, blitter.get()); 319} 320 321/////////////////////////////////////////////////////////////////////////////// 322 323struct PtProcRec { 324 SkCanvas::PointMode fMode; 325 const SkPaint* fPaint; 326 const SkRegion* fClip; 327 const SkRasterClip* fRC; 328 329 // computed values 330 SkFixed fRadius; 331 332 typedef void (*Proc)(const PtProcRec&, const SkPoint devPts[], int count, 333 SkBlitter*); 334 335 bool init(SkCanvas::PointMode, const SkPaint&, const SkMatrix* matrix, 336 const SkRasterClip*); 337 Proc chooseProc(SkBlitter** blitter); 338 339private: 340 SkAAClipBlitterWrapper fWrapper; 341}; 342 343static void bw_pt_rect_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 344 int count, SkBlitter* blitter) { 345 SkASSERT(rec.fClip->isRect()); 346 const SkIRect& r = rec.fClip->getBounds(); 347 348 for (int i = 0; i < count; i++) { 349 int x = SkScalarFloorToInt(devPts[i].fX); 350 int y = SkScalarFloorToInt(devPts[i].fY); 351 if (r.contains(x, y)) { 352 blitter->blitH(x, y, 1); 353 } 354 } 355} 356 357static void bw_pt_rect_16_hair_proc(const PtProcRec& rec, 358 const SkPoint devPts[], int count, 359 SkBlitter* blitter) { 360 SkASSERT(rec.fRC->isRect()); 361 const SkIRect& r = rec.fRC->getBounds(); 362 uint32_t value; 363 const SkBitmap* bitmap = blitter->justAnOpaqueColor(&value); 364 SkASSERT(bitmap); 365 366 uint16_t* addr = bitmap->getAddr16(0, 0); 367 size_t rb = bitmap->rowBytes(); 368 369 for (int i = 0; i < count; i++) { 370 int x = SkScalarFloorToInt(devPts[i].fX); 371 int y = SkScalarFloorToInt(devPts[i].fY); 372 if (r.contains(x, y)) { 373 ((uint16_t*)((char*)addr + y * rb))[x] = SkToU16(value); 374 } 375 } 376} 377 378static void bw_pt_rect_32_hair_proc(const PtProcRec& rec, 379 const SkPoint devPts[], int count, 380 SkBlitter* blitter) { 381 SkASSERT(rec.fRC->isRect()); 382 const SkIRect& r = rec.fRC->getBounds(); 383 uint32_t value; 384 const SkBitmap* bitmap = blitter->justAnOpaqueColor(&value); 385 SkASSERT(bitmap); 386 387 SkPMColor* addr = bitmap->getAddr32(0, 0); 388 size_t rb = bitmap->rowBytes(); 389 390 for (int i = 0; i < count; i++) { 391 int x = SkScalarFloorToInt(devPts[i].fX); 392 int y = SkScalarFloorToInt(devPts[i].fY); 393 if (r.contains(x, y)) { 394 ((SkPMColor*)((char*)addr + y * rb))[x] = value; 395 } 396 } 397} 398 399static void bw_pt_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 400 int count, SkBlitter* blitter) { 401 for (int i = 0; i < count; i++) { 402 int x = SkScalarFloor(devPts[i].fX); 403 int y = SkScalarFloor(devPts[i].fY); 404 if (rec.fClip->contains(x, y)) { 405 blitter->blitH(x, y, 1); 406 } 407 } 408} 409 410static void bw_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 411 int count, SkBlitter* blitter) { 412 for (int i = 0; i < count; i += 2) { 413 SkScan::HairLine(devPts[i], devPts[i+1], *rec.fRC, blitter); 414 } 415} 416 417static void bw_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 418 int count, SkBlitter* blitter) { 419 for (int i = 0; i < count - 1; i++) { 420 SkScan::HairLine(devPts[i], devPts[i+1], *rec.fRC, blitter); 421 } 422} 423 424// aa versions 425 426static void aa_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 427 int count, SkBlitter* blitter) { 428 for (int i = 0; i < count; i += 2) { 429 SkScan::AntiHairLine(devPts[i], devPts[i+1], *rec.fRC, blitter); 430 } 431} 432 433static void aa_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 434 int count, SkBlitter* blitter) { 435 for (int i = 0; i < count - 1; i++) { 436 SkScan::AntiHairLine(devPts[i], devPts[i+1], *rec.fRC, blitter); 437 } 438} 439 440// square procs (strokeWidth > 0 but matrix is square-scale (sx == sy) 441 442static void bw_square_proc(const PtProcRec& rec, const SkPoint devPts[], 443 int count, SkBlitter* blitter) { 444 const SkFixed radius = rec.fRadius; 445 for (int i = 0; i < count; i++) { 446 SkFixed x = SkScalarToFixed(devPts[i].fX); 447 SkFixed y = SkScalarToFixed(devPts[i].fY); 448 449 SkXRect r; 450 r.fLeft = x - radius; 451 r.fTop = y - radius; 452 r.fRight = x + radius; 453 r.fBottom = y + radius; 454 455 SkScan::FillXRect(r, *rec.fRC, blitter); 456 } 457} 458 459static void aa_square_proc(const PtProcRec& rec, const SkPoint devPts[], 460 int count, SkBlitter* blitter) { 461 const SkFixed radius = rec.fRadius; 462 for (int i = 0; i < count; i++) { 463 SkFixed x = SkScalarToFixed(devPts[i].fX); 464 SkFixed y = SkScalarToFixed(devPts[i].fY); 465 466 SkXRect r; 467 r.fLeft = x - radius; 468 r.fTop = y - radius; 469 r.fRight = x + radius; 470 r.fBottom = y + radius; 471 472 SkScan::AntiFillXRect(r, *rec.fRC, blitter); 473 } 474} 475 476// If this guy returns true, then chooseProc() must return a valid proc 477bool PtProcRec::init(SkCanvas::PointMode mode, const SkPaint& paint, 478 const SkMatrix* matrix, const SkRasterClip* rc) { 479 if (paint.getPathEffect()) { 480 return false; 481 } 482 SkScalar width = paint.getStrokeWidth(); 483 if (0 == width) { 484 fMode = mode; 485 fPaint = &paint; 486 fClip = NULL; 487 fRC = rc; 488 fRadius = SK_FixedHalf; 489 return true; 490 } 491 if (paint.getStrokeCap() != SkPaint::kRound_Cap && 492 matrix->rectStaysRect() && SkCanvas::kPoints_PointMode == mode) { 493 SkScalar sx = matrix->get(SkMatrix::kMScaleX); 494 SkScalar sy = matrix->get(SkMatrix::kMScaleY); 495 if (SkScalarNearlyZero(sx - sy)) { 496 if (sx < 0) { 497 sx = -sx; 498 } 499 500 fMode = mode; 501 fPaint = &paint; 502 fClip = NULL; 503 fRC = rc; 504 fRadius = SkScalarToFixed(SkScalarMul(width, sx)) >> 1; 505 return true; 506 } 507 } 508 return false; 509} 510 511PtProcRec::Proc PtProcRec::chooseProc(SkBlitter** blitterPtr) { 512 Proc proc = NULL; 513 514 SkBlitter* blitter = *blitterPtr; 515 if (fRC->isBW()) { 516 fClip = &fRC->bwRgn(); 517 } else { 518 fWrapper.init(*fRC, blitter); 519 fClip = &fWrapper.getRgn(); 520 blitter = fWrapper.getBlitter(); 521 *blitterPtr = blitter; 522 } 523 524 // for our arrays 525 SkASSERT(0 == SkCanvas::kPoints_PointMode); 526 SkASSERT(1 == SkCanvas::kLines_PointMode); 527 SkASSERT(2 == SkCanvas::kPolygon_PointMode); 528 SkASSERT((unsigned)fMode <= (unsigned)SkCanvas::kPolygon_PointMode); 529 530 if (fPaint->isAntiAlias()) { 531 if (0 == fPaint->getStrokeWidth()) { 532 static const Proc gAAProcs[] = { 533 aa_square_proc, aa_line_hair_proc, aa_poly_hair_proc 534 }; 535 proc = gAAProcs[fMode]; 536 } else if (fPaint->getStrokeCap() != SkPaint::kRound_Cap) { 537 SkASSERT(SkCanvas::kPoints_PointMode == fMode); 538 proc = aa_square_proc; 539 } 540 } else { // BW 541 if (fRadius <= SK_FixedHalf) { // small radii and hairline 542 if (SkCanvas::kPoints_PointMode == fMode && fClip->isRect()) { 543 uint32_t value; 544 const SkBitmap* bm = blitter->justAnOpaqueColor(&value); 545 if (bm && SkBitmap::kRGB_565_Config == bm->config()) { 546 proc = bw_pt_rect_16_hair_proc; 547 } else if (bm && SkBitmap::kARGB_8888_Config == bm->config()) { 548 proc = bw_pt_rect_32_hair_proc; 549 } else { 550 proc = bw_pt_rect_hair_proc; 551 } 552 } else { 553 static Proc gBWProcs[] = { 554 bw_pt_hair_proc, bw_line_hair_proc, bw_poly_hair_proc 555 }; 556 proc = gBWProcs[fMode]; 557 } 558 } else { 559 proc = bw_square_proc; 560 } 561 } 562 return proc; 563} 564 565static bool bounder_points(SkBounder* bounder, SkCanvas::PointMode mode, 566 size_t count, const SkPoint pts[], 567 const SkPaint& paint, const SkMatrix& matrix) { 568 SkIRect ibounds; 569 SkRect bounds; 570 SkScalar inset = paint.getStrokeWidth(); 571 572 bounds.set(pts, count); 573 bounds.inset(-inset, -inset); 574 matrix.mapRect(&bounds); 575 576 bounds.roundOut(&ibounds); 577 return bounder->doIRect(ibounds); 578} 579 580// each of these costs 8-bytes of stack space, so don't make it too large 581// must be even for lines/polygon to work 582#define MAX_DEV_PTS 32 583 584void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count, 585 const SkPoint pts[], const SkPaint& paint, 586 bool forceUseDevice) const { 587 // if we're in lines mode, force count to be even 588 if (SkCanvas::kLines_PointMode == mode) { 589 count &= ~(size_t)1; 590 } 591 592 if ((long)count <= 0) { 593 return; 594 } 595 596 SkASSERT(pts != NULL); 597 SkDEBUGCODE(this->validate();) 598 599 // nothing to draw 600 if (fRC->isEmpty()) { 601 return; 602 } 603 604 if (fBounder) { 605 if (!bounder_points(fBounder, mode, count, pts, paint, *fMatrix)) { 606 return; 607 } 608 609 // clear the bounder and call this again, so we don't invoke the bounder 610 // later if we happen to call ourselves for drawRect, drawPath, etc. 611 SkDraw noBounder(*this); 612 noBounder.fBounder = NULL; 613 noBounder.drawPoints(mode, count, pts, paint, forceUseDevice); 614 return; 615 } 616 617 PtProcRec rec; 618 if (!forceUseDevice && rec.init(mode, paint, fMatrix, fRC)) { 619 SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint); 620 621 SkPoint devPts[MAX_DEV_PTS]; 622 const SkMatrix* matrix = fMatrix; 623 SkBlitter* bltr = blitter.get(); 624 PtProcRec::Proc proc = rec.chooseProc(&bltr); 625 // we have to back up subsequent passes if we're in polygon mode 626 const size_t backup = (SkCanvas::kPolygon_PointMode == mode); 627 628 do { 629 size_t n = count; 630 if (n > MAX_DEV_PTS) { 631 n = MAX_DEV_PTS; 632 } 633 matrix->mapPoints(devPts, pts, n); 634 proc(rec, devPts, n, bltr); 635 pts += n - backup; 636 SkASSERT(count >= n); 637 count -= n; 638 if (count > 0) { 639 count += backup; 640 } 641 } while (count != 0); 642 } else { 643 switch (mode) { 644 case SkCanvas::kPoints_PointMode: { 645 // temporarily mark the paint as filling. 646 SkPaint newPaint(paint); 647 newPaint.setStyle(SkPaint::kFill_Style); 648 649 SkScalar width = newPaint.getStrokeWidth(); 650 SkScalar radius = SkScalarHalf(width); 651 652 if (newPaint.getStrokeCap() == SkPaint::kRound_Cap) { 653 SkPath path; 654 SkMatrix preMatrix; 655 656 path.addCircle(0, 0, radius); 657 for (size_t i = 0; i < count; i++) { 658 preMatrix.setTranslate(pts[i].fX, pts[i].fY); 659 // pass true for the last point, since we can modify 660 // then path then 661 if (fDevice) { 662 fDevice->drawPath(*this, path, newPaint, &preMatrix, 663 (count-1) == i); 664 } else { 665 this->drawPath(path, newPaint, &preMatrix, 666 (count-1) == i); 667 } 668 } 669 } else { 670 SkRect r; 671 672 for (size_t i = 0; i < count; i++) { 673 r.fLeft = pts[i].fX - radius; 674 r.fTop = pts[i].fY - radius; 675 r.fRight = r.fLeft + width; 676 r.fBottom = r.fTop + width; 677 if (fDevice) { 678 fDevice->drawRect(*this, r, newPaint); 679 } else { 680 this->drawRect(r, newPaint); 681 } 682 } 683 } 684 break; 685 } 686 case SkCanvas::kLines_PointMode: 687#ifndef SK_DISABLE_DASHING_OPTIMIZATION 688 if (2 == count && NULL != paint.getPathEffect()) { 689 // most likely a dashed line - see if it is one of the ones 690 // we can accelerate 691 SkStrokeRec rec(paint); 692 SkPathEffect::PointData pointData; 693 694 SkPath path; 695 path.moveTo(pts[0]); 696 path.lineTo(pts[1]); 697 698 SkRect cullRect = SkRect::Make(fRC->getBounds()); 699 700 if (paint.getPathEffect()->asPoints(&pointData, path, rec, 701 *fMatrix, &cullRect)) { 702 // 'asPoints' managed to find some fast path 703 704 SkPaint newP(paint); 705 newP.setPathEffect(NULL); 706 newP.setStyle(SkPaint::kFill_Style); 707 708 if (!pointData.fFirst.isEmpty()) { 709 if (fDevice) { 710 fDevice->drawPath(*this, pointData.fFirst, newP); 711 } else { 712 this->drawPath(pointData.fFirst, newP); 713 } 714 } 715 716 if (!pointData.fLast.isEmpty()) { 717 if (fDevice) { 718 fDevice->drawPath(*this, pointData.fLast, newP); 719 } else { 720 this->drawPath(pointData.fLast, newP); 721 } 722 } 723 724 if (pointData.fSize.fX == pointData.fSize.fY) { 725 // The rest of the dashed line can just be drawn as points 726 SkASSERT(pointData.fSize.fX == SkScalarHalf(newP.getStrokeWidth())); 727 728 if (SkPathEffect::PointData::kCircles_PointFlag & pointData.fFlags) { 729 newP.setStrokeCap(SkPaint::kRound_Cap); 730 } else { 731 newP.setStrokeCap(SkPaint::kButt_Cap); 732 } 733 734 if (fDevice) { 735 fDevice->drawPoints(*this, 736 SkCanvas::kPoints_PointMode, 737 pointData.fNumPoints, 738 pointData.fPoints, 739 newP); 740 } else { 741 this->drawPoints(SkCanvas::kPoints_PointMode, 742 pointData.fNumPoints, 743 pointData.fPoints, 744 newP, 745 forceUseDevice); 746 } 747 break; 748 } else { 749 // The rest of the dashed line must be drawn as rects 750 SkASSERT(!(SkPathEffect::PointData::kCircles_PointFlag & 751 pointData.fFlags)); 752 753 SkRect r; 754 755 for (int i = 0; i < pointData.fNumPoints; ++i) { 756 r.set(pointData.fPoints[i].fX - pointData.fSize.fX, 757 pointData.fPoints[i].fY - pointData.fSize.fY, 758 pointData.fPoints[i].fX + pointData.fSize.fX, 759 pointData.fPoints[i].fY + pointData.fSize.fY); 760 if (fDevice) { 761 fDevice->drawRect(*this, r, newP); 762 } else { 763 this->drawRect(r, newP); 764 } 765 } 766 } 767 768 break; 769 } 770 } 771#endif // DISABLE_DASHING_OPTIMIZATION 772 // couldn't take fast path so fall through! 773 case SkCanvas::kPolygon_PointMode: { 774 count -= 1; 775 SkPath path; 776 SkPaint p(paint); 777 p.setStyle(SkPaint::kStroke_Style); 778 size_t inc = (SkCanvas::kLines_PointMode == mode) ? 2 : 1; 779 for (size_t i = 0; i < count; i += inc) { 780 path.moveTo(pts[i]); 781 path.lineTo(pts[i+1]); 782 if (fDevice) { 783 fDevice->drawPath(*this, path, p, NULL, true); 784 } else { 785 this->drawPath(path, p, NULL, true); 786 } 787 path.rewind(); 788 } 789 break; 790 } 791 } 792 } 793} 794 795static bool easy_rect_join(const SkPaint& paint, const SkMatrix& matrix, 796 SkPoint* strokeSize) { 797 if (SkPaint::kMiter_Join != paint.getStrokeJoin() || 798 paint.getStrokeMiter() < SK_ScalarSqrt2) { 799 return false; 800 } 801 802 SkASSERT(matrix.rectStaysRect()); 803 SkPoint pt = { paint.getStrokeWidth(), paint.getStrokeWidth() }; 804 matrix.mapVectors(strokeSize, &pt, 1); 805 strokeSize->fX = SkScalarAbs(strokeSize->fX); 806 strokeSize->fY = SkScalarAbs(strokeSize->fY); 807 return true; 808} 809 810SkDraw::RectType SkDraw::ComputeRectType(const SkPaint& paint, 811 const SkMatrix& matrix, 812 SkPoint* strokeSize) { 813 RectType rtype; 814 const SkScalar width = paint.getStrokeWidth(); 815 const bool zeroWidth = (0 == width); 816 SkPaint::Style style = paint.getStyle(); 817 818 if ((SkPaint::kStrokeAndFill_Style == style) && zeroWidth) { 819 style = SkPaint::kFill_Style; 820 } 821 822 if (paint.getPathEffect() || paint.getMaskFilter() || 823 paint.getRasterizer() || !matrix.rectStaysRect() || 824 SkPaint::kStrokeAndFill_Style == style) { 825 rtype = kPath_RectType; 826 } else if (SkPaint::kFill_Style == style) { 827 rtype = kFill_RectType; 828 } else if (zeroWidth) { 829 rtype = kHair_RectType; 830 } else if (easy_rect_join(paint, matrix, strokeSize)) { 831 rtype = kStroke_RectType; 832 } else { 833 rtype = kPath_RectType; 834 } 835 return rtype; 836} 837 838static const SkPoint* rect_points(const SkRect& r) { 839 return SkTCast<const SkPoint*>(&r); 840} 841 842static SkPoint* rect_points(SkRect& r) { 843 return SkTCast<SkPoint*>(&r); 844} 845 846void SkDraw::drawRect(const SkRect& rect, const SkPaint& paint) const { 847 SkDEBUGCODE(this->validate();) 848 849 // nothing to draw 850 if (fRC->isEmpty()) { 851 return; 852 } 853 854 SkPoint strokeSize; 855 RectType rtype = ComputeRectType(paint, *fMatrix, &strokeSize); 856 857 if (kPath_RectType == rtype) { 858 SkPath tmp; 859 tmp.addRect(rect); 860 tmp.setFillType(SkPath::kWinding_FillType); 861 this->drawPath(tmp, paint, NULL, true); 862 return; 863 } 864 865 const SkMatrix& matrix = *fMatrix; 866 SkRect devRect; 867 868 // transform rect into devRect 869 matrix.mapPoints(rect_points(devRect), rect_points(rect), 2); 870 devRect.sort(); 871 872 if (fBounder && !fBounder->doRect(devRect, paint)) { 873 return; 874 } 875 876 // look for the quick exit, before we build a blitter 877 SkIRect ir; 878 devRect.roundOut(&ir); 879 if (paint.getStyle() != SkPaint::kFill_Style) { 880 // extra space for hairlines 881 ir.inset(-1, -1); 882 } 883 if (fRC->quickReject(ir)) { 884 return; 885 } 886 887 SkDeviceLooper looper(*fBitmap, *fRC, ir, paint.isAntiAlias()); 888 while (looper.next()) { 889 SkRect localDevRect; 890 looper.mapRect(&localDevRect, devRect); 891 SkMatrix localMatrix; 892 looper.mapMatrix(&localMatrix, matrix); 893 894 SkAutoBlitterChoose blitterStorage(looper.getBitmap(), localMatrix, 895 paint); 896 const SkRasterClip& clip = looper.getRC(); 897 SkBlitter* blitter = blitterStorage.get(); 898 899 // we want to "fill" if we are kFill or kStrokeAndFill, since in the latter 900 // case we are also hairline (if we've gotten to here), which devolves to 901 // effectively just kFill 902 switch (rtype) { 903 case kFill_RectType: 904 if (paint.isAntiAlias()) { 905 SkScan::AntiFillRect(localDevRect, clip, blitter); 906 } else { 907 SkScan::FillRect(localDevRect, clip, blitter); 908 } 909 break; 910 case kStroke_RectType: 911 if (paint.isAntiAlias()) { 912 SkScan::AntiFrameRect(localDevRect, strokeSize, clip, blitter); 913 } else { 914 SkScan::FrameRect(localDevRect, strokeSize, clip, blitter); 915 } 916 break; 917 case kHair_RectType: 918 if (paint.isAntiAlias()) { 919 SkScan::AntiHairRect(localDevRect, clip, blitter); 920 } else { 921 SkScan::HairRect(localDevRect, clip, blitter); 922 } 923 break; 924 default: 925 SkDEBUGFAIL("bad rtype"); 926 } 927 } 928} 929 930void SkDraw::drawDevMask(const SkMask& srcM, const SkPaint& paint) const { 931 if (srcM.fBounds.isEmpty()) { 932 return; 933 } 934 935 const SkMask* mask = &srcM; 936 937 SkMask dstM; 938 if (paint.getMaskFilter() && 939 paint.getMaskFilter()->filterMask(&dstM, srcM, *fMatrix, NULL)) { 940 mask = &dstM; 941 } else { 942 dstM.fImage = NULL; 943 } 944 SkAutoMaskFreeImage ami(dstM.fImage); 945 946 if (fBounder && !fBounder->doIRect(mask->fBounds)) { 947 return; 948 } 949 950 SkAutoBlitterChoose blitterChooser(*fBitmap, *fMatrix, paint); 951 SkBlitter* blitter = blitterChooser.get(); 952 953 SkAAClipBlitterWrapper wrapper; 954 const SkRegion* clipRgn; 955 956 if (fRC->isBW()) { 957 clipRgn = &fRC->bwRgn(); 958 } else { 959 wrapper.init(*fRC, blitter); 960 clipRgn = &wrapper.getRgn(); 961 blitter = wrapper.getBlitter(); 962 } 963 blitter->blitMaskRegion(*mask, *clipRgn); 964} 965 966static SkScalar fast_len(const SkVector& vec) { 967 SkScalar x = SkScalarAbs(vec.fX); 968 SkScalar y = SkScalarAbs(vec.fY); 969 if (x < y) { 970 SkTSwap(x, y); 971 } 972 return x + SkScalarHalf(y); 973} 974 975static bool xfermodeSupportsCoverageAsAlpha(SkXfermode* xfer) { 976 SkXfermode::Coeff dc; 977 if (!SkXfermode::AsCoeff(xfer, NULL, &dc)) { 978 return false; 979 } 980 981 switch (dc) { 982 case SkXfermode::kOne_Coeff: 983 case SkXfermode::kISA_Coeff: 984 case SkXfermode::kISC_Coeff: 985 return true; 986 default: 987 return false; 988 } 989} 990 991bool SkDrawTreatAsHairline(const SkPaint& paint, const SkMatrix& matrix, 992 SkScalar* coverage) { 993 SkASSERT(coverage); 994 if (SkPaint::kStroke_Style != paint.getStyle()) { 995 return false; 996 } 997 SkScalar strokeWidth = paint.getStrokeWidth(); 998 if (0 == strokeWidth) { 999 *coverage = SK_Scalar1; 1000 return true; 1001 } 1002 1003 // if we get here, we need to try to fake a thick-stroke with a modulated 1004 // hairline 1005 1006 if (!paint.isAntiAlias()) { 1007 return false; 1008 } 1009 if (matrix.hasPerspective()) { 1010 return false; 1011 } 1012 1013 SkVector src[2], dst[2]; 1014 src[0].set(strokeWidth, 0); 1015 src[1].set(0, strokeWidth); 1016 matrix.mapVectors(dst, src, 2); 1017 SkScalar len0 = fast_len(dst[0]); 1018 SkScalar len1 = fast_len(dst[1]); 1019 if (len0 <= SK_Scalar1 && len1 <= SK_Scalar1) { 1020 *coverage = SkScalarAve(len0, len1); 1021 return true; 1022 } 1023 return false; 1024} 1025 1026void SkDraw::drawRRect(const SkRRect& rrect, const SkPaint& paint) const { 1027 SkDEBUGCODE(this->validate()); 1028 1029 if (fRC->isEmpty()) { 1030 return; 1031 } 1032 1033 { 1034 // TODO: Investigate optimizing these options. They are in the same 1035 // order as SkDraw::drawPath, which handles each case. It may be 1036 // that there is no way to optimize for these using the SkRRect path. 1037 SkScalar coverage; 1038 if (SkDrawTreatAsHairline(paint, *fMatrix, &coverage)) { 1039 goto DRAW_PATH; 1040 } 1041 1042 if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) { 1043 goto DRAW_PATH; 1044 } 1045 1046 if (paint.getRasterizer()) { 1047 goto DRAW_PATH; 1048 } 1049 } 1050 1051 if (paint.getMaskFilter()) { 1052 // Transform the rrect into device space. 1053 SkRRect devRRect; 1054 if (rrect.transform(*fMatrix, &devRRect)) { 1055 SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint); 1056 if (paint.getMaskFilter()->filterRRect(devRRect, *fMatrix, *fRC, 1057 fBounder, blitter.get(), 1058 SkPaint::kFill_Style)) { 1059 return; // filterRRect() called the blitter, so we're done 1060 } 1061 } 1062 } 1063 1064DRAW_PATH: 1065 // Now fall back to the default case of using a path. 1066 SkPath path; 1067 path.addRRect(rrect); 1068 this->drawPath(path, paint, NULL, true); 1069} 1070 1071void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint, 1072 const SkMatrix* prePathMatrix, bool pathIsMutable) const { 1073 SkDEBUGCODE(this->validate();) 1074 1075 // nothing to draw 1076 if (fRC->isEmpty()) { 1077 return; 1078 } 1079 1080 SkPath* pathPtr = (SkPath*)&origSrcPath; 1081 bool doFill = true; 1082 SkPath tmpPath; 1083 SkMatrix tmpMatrix; 1084 const SkMatrix* matrix = fMatrix; 1085 1086 if (prePathMatrix) { 1087 if (origPaint.getPathEffect() || origPaint.getStyle() != SkPaint::kFill_Style || 1088 origPaint.getRasterizer()) { 1089 SkPath* result = pathPtr; 1090 1091 if (!pathIsMutable) { 1092 result = &tmpPath; 1093 pathIsMutable = true; 1094 } 1095 pathPtr->transform(*prePathMatrix, result); 1096 pathPtr = result; 1097 } else { 1098 if (!tmpMatrix.setConcat(*matrix, *prePathMatrix)) { 1099 // overflow 1100 return; 1101 } 1102 matrix = &tmpMatrix; 1103 } 1104 } 1105 // at this point we're done with prePathMatrix 1106 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;) 1107 1108 SkTCopyOnFirstWrite<SkPaint> paint(origPaint); 1109 1110 { 1111 SkScalar coverage; 1112 if (SkDrawTreatAsHairline(origPaint, *matrix, &coverage)) { 1113 if (SK_Scalar1 == coverage) { 1114 paint.writable()->setStrokeWidth(0); 1115 } else if (xfermodeSupportsCoverageAsAlpha(origPaint.getXfermode())) { 1116 U8CPU newAlpha; 1117#if 0 1118 newAlpha = SkToU8(SkScalarRoundToInt(coverage * 1119 origPaint.getAlpha())); 1120#else 1121 // this is the old technique, which we preserve for now so 1122 // we don't change previous results (testing) 1123 // the new way seems fine, its just (a tiny bit) different 1124 int scale = (int)SkScalarMul(coverage, 256); 1125 newAlpha = origPaint.getAlpha() * scale >> 8; 1126#endif 1127 SkPaint* writablePaint = paint.writable(); 1128 writablePaint->setStrokeWidth(0); 1129 writablePaint->setAlpha(newAlpha); 1130 } 1131 } 1132 } 1133 1134 if (paint->getPathEffect() || paint->getStyle() != SkPaint::kFill_Style) { 1135 SkRect cullRect; 1136 const SkRect* cullRectPtr = NULL; 1137 if (this->computeConservativeLocalClipBounds(&cullRect)) { 1138 cullRectPtr = &cullRect; 1139 } 1140 doFill = paint->getFillPath(*pathPtr, &tmpPath, cullRectPtr); 1141 pathPtr = &tmpPath; 1142 } 1143 1144 if (paint->getRasterizer()) { 1145 SkMask mask; 1146 if (paint->getRasterizer()->rasterize(*pathPtr, *matrix, 1147 &fRC->getBounds(), paint->getMaskFilter(), &mask, 1148 SkMask::kComputeBoundsAndRenderImage_CreateMode)) { 1149 this->drawDevMask(mask, *paint); 1150 SkMask::FreeImage(mask.fImage); 1151 } 1152 return; 1153 } 1154 1155 // avoid possibly allocating a new path in transform if we can 1156 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath; 1157 1158 // transform the path into device space 1159 pathPtr->transform(*matrix, devPathPtr); 1160 1161 SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, *paint); 1162 1163 if (paint->getMaskFilter()) { 1164 SkPaint::Style style = doFill ? SkPaint::kFill_Style : 1165 SkPaint::kStroke_Style; 1166 if (paint->getMaskFilter()->filterPath(*devPathPtr, *fMatrix, *fRC, 1167 fBounder, blitter.get(), 1168 style)) { 1169 return; // filterPath() called the blitter, so we're done 1170 } 1171 } 1172 1173 if (fBounder && !fBounder->doPath(*devPathPtr, *paint, doFill)) { 1174 return; 1175 } 1176 1177 void (*proc)(const SkPath&, const SkRasterClip&, SkBlitter*); 1178 if (doFill) { 1179 if (paint->isAntiAlias()) { 1180 proc = SkScan::AntiFillPath; 1181 } else { 1182 proc = SkScan::FillPath; 1183 } 1184 } else { // hairline 1185 if (paint->isAntiAlias()) { 1186 proc = SkScan::AntiHairPath; 1187 } else { 1188 proc = SkScan::HairPath; 1189 } 1190 } 1191 proc(*devPathPtr, *fRC, blitter.get()); 1192} 1193 1194/** For the purposes of drawing bitmaps, if a matrix is "almost" translate 1195 go ahead and treat it as if it were, so that subsequent code can go fast. 1196 */ 1197static bool just_translate(const SkMatrix& matrix, const SkBitmap& bitmap) { 1198 unsigned bits = 0; // TODO: find a way to allow the caller to tell us to 1199 // respect filtering. 1200 return SkTreatAsSprite(matrix, bitmap.width(), bitmap.height(), bits); 1201} 1202 1203void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap, 1204 const SkPaint& paint) const { 1205 SkASSERT(bitmap.getConfig() == SkBitmap::kA8_Config); 1206 1207 if (just_translate(*fMatrix, bitmap)) { 1208 int ix = SkScalarRound(fMatrix->getTranslateX()); 1209 int iy = SkScalarRound(fMatrix->getTranslateY()); 1210 1211 SkAutoLockPixels alp(bitmap); 1212 if (!bitmap.readyToDraw()) { 1213 return; 1214 } 1215 1216 SkMask mask; 1217 mask.fBounds.set(ix, iy, ix + bitmap.width(), iy + bitmap.height()); 1218 mask.fFormat = SkMask::kA8_Format; 1219 mask.fRowBytes = SkToU32(bitmap.rowBytes()); 1220 mask.fImage = bitmap.getAddr8(0, 0); 1221 1222 this->drawDevMask(mask, paint); 1223 } else { // need to xform the bitmap first 1224 SkRect r; 1225 SkMask mask; 1226 1227 r.set(0, 0, 1228 SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height())); 1229 fMatrix->mapRect(&r); 1230 r.round(&mask.fBounds); 1231 1232 // set the mask's bounds to the transformed bitmap-bounds, 1233 // clipped to the actual device 1234 { 1235 SkIRect devBounds; 1236 devBounds.set(0, 0, fBitmap->width(), fBitmap->height()); 1237 // need intersect(l, t, r, b) on irect 1238 if (!mask.fBounds.intersect(devBounds)) { 1239 return; 1240 } 1241 } 1242 1243 mask.fFormat = SkMask::kA8_Format; 1244 mask.fRowBytes = SkAlign4(mask.fBounds.width()); 1245 size_t size = mask.computeImageSize(); 1246 if (0 == size) { 1247 // the mask is too big to allocated, draw nothing 1248 return; 1249 } 1250 1251 // allocate (and clear) our temp buffer to hold the transformed bitmap 1252 SkAutoMalloc storage(size); 1253 mask.fImage = (uint8_t*)storage.get(); 1254 memset(mask.fImage, 0, size); 1255 1256 // now draw our bitmap(src) into mask(dst), transformed by the matrix 1257 { 1258 SkBitmap device; 1259 device.setConfig(SkBitmap::kA8_Config, mask.fBounds.width(), 1260 mask.fBounds.height(), mask.fRowBytes); 1261 device.setPixels(mask.fImage); 1262 1263 SkCanvas c(device); 1264 // need the unclipped top/left for the translate 1265 c.translate(-SkIntToScalar(mask.fBounds.fLeft), 1266 -SkIntToScalar(mask.fBounds.fTop)); 1267 c.concat(*fMatrix); 1268 1269 // We can't call drawBitmap, or we'll infinitely recurse. Instead 1270 // we manually build a shader and draw that into our new mask 1271 SkPaint tmpPaint; 1272 tmpPaint.setFlags(paint.getFlags()); 1273 SkAutoBitmapShaderInstall install(bitmap, tmpPaint); 1274 SkRect rr; 1275 rr.set(0, 0, SkIntToScalar(bitmap.width()), 1276 SkIntToScalar(bitmap.height())); 1277 c.drawRect(rr, install.paintWithShader()); 1278 } 1279 this->drawDevMask(mask, paint); 1280 } 1281} 1282 1283static bool clipped_out(const SkMatrix& m, const SkRasterClip& c, 1284 const SkRect& srcR) { 1285 SkRect dstR; 1286 SkIRect devIR; 1287 1288 m.mapRect(&dstR, srcR); 1289 dstR.roundOut(&devIR); 1290 return c.quickReject(devIR); 1291} 1292 1293static bool clipped_out(const SkMatrix& matrix, const SkRasterClip& clip, 1294 int width, int height) { 1295 SkRect r; 1296 r.set(0, 0, SkIntToScalar(width), SkIntToScalar(height)); 1297 return clipped_out(matrix, clip, r); 1298} 1299 1300static bool clipHandlesSprite(const SkRasterClip& clip, int x, int y, 1301 const SkBitmap& bitmap) { 1302 return clip.isBW() || 1303 clip.quickContains(x, y, x + bitmap.width(), y + bitmap.height()); 1304} 1305 1306void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix, 1307 const SkPaint& origPaint) const { 1308 SkDEBUGCODE(this->validate();) 1309 1310 // nothing to draw 1311 if (fRC->isEmpty() || 1312 bitmap.width() == 0 || bitmap.height() == 0 || 1313 bitmap.getConfig() == SkBitmap::kNo_Config) { 1314 return; 1315 } 1316 1317 SkPaint paint(origPaint); 1318 paint.setStyle(SkPaint::kFill_Style); 1319 1320 SkMatrix matrix; 1321 if (!matrix.setConcat(*fMatrix, prematrix)) { 1322 return; 1323 } 1324 1325 if (clipped_out(matrix, *fRC, bitmap.width(), bitmap.height())) { 1326 return; 1327 } 1328 1329 if (fBounder && just_translate(matrix, bitmap)) { 1330 SkIRect ir; 1331 int32_t ix = SkScalarRound(matrix.getTranslateX()); 1332 int32_t iy = SkScalarRound(matrix.getTranslateY()); 1333 ir.set(ix, iy, ix + bitmap.width(), iy + bitmap.height()); 1334 if (!fBounder->doIRect(ir)) { 1335 return; 1336 } 1337 } 1338 1339 if (bitmap.getConfig() != SkBitmap::kA8_Config && 1340 just_translate(matrix, bitmap)) { 1341 // 1342 // It is safe to call lock pixels now, since we know the matrix is 1343 // (more or less) identity. 1344 // 1345 SkAutoLockPixels alp(bitmap); 1346 if (!bitmap.readyToDraw()) { 1347 return; 1348 } 1349 int ix = SkScalarRound(matrix.getTranslateX()); 1350 int iy = SkScalarRound(matrix.getTranslateY()); 1351 if (clipHandlesSprite(*fRC, ix, iy, bitmap)) { 1352 uint32_t storage[kBlitterStorageLongCount]; 1353 SkBlitter* blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap, 1354 ix, iy, storage, sizeof(storage)); 1355 if (blitter) { 1356 SkAutoTPlacementDelete<SkBlitter> ad(blitter, storage); 1357 1358 SkIRect ir; 1359 ir.set(ix, iy, ix + bitmap.width(), iy + bitmap.height()); 1360 1361 SkScan::FillIRect(ir, *fRC, blitter); 1362 return; 1363 } 1364 } 1365 } 1366 1367 // now make a temp draw on the stack, and use it 1368 // 1369 SkDraw draw(*this); 1370 draw.fMatrix = &matrix; 1371 1372 if (bitmap.getConfig() == SkBitmap::kA8_Config) { 1373 draw.drawBitmapAsMask(bitmap, paint); 1374 } else { 1375 SkAutoBitmapShaderInstall install(bitmap, paint); 1376 1377 SkRect r; 1378 r.set(0, 0, SkIntToScalar(bitmap.width()), 1379 SkIntToScalar(bitmap.height())); 1380 // is this ok if paint has a rasterizer? 1381 draw.drawRect(r, install.paintWithShader()); 1382 } 1383} 1384 1385void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y, 1386 const SkPaint& origPaint) const { 1387 SkDEBUGCODE(this->validate();) 1388 1389 // nothing to draw 1390 if (fRC->isEmpty() || 1391 bitmap.width() == 0 || bitmap.height() == 0 || 1392 bitmap.getConfig() == SkBitmap::kNo_Config) { 1393 return; 1394 } 1395 1396 SkIRect bounds; 1397 bounds.set(x, y, x + bitmap.width(), y + bitmap.height()); 1398 1399 if (fRC->quickReject(bounds)) { 1400 return; // nothing to draw 1401 } 1402 1403 SkPaint paint(origPaint); 1404 paint.setStyle(SkPaint::kFill_Style); 1405 1406 if (NULL == paint.getColorFilter() && clipHandlesSprite(*fRC, x, y, bitmap)) { 1407 uint32_t storage[kBlitterStorageLongCount]; 1408 SkBlitter* blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap, 1409 x, y, storage, sizeof(storage)); 1410 1411 if (blitter) { 1412 SkAutoTPlacementDelete<SkBlitter> ad(blitter, storage); 1413 1414 if (fBounder && !fBounder->doIRect(bounds)) { 1415 return; 1416 } 1417 1418 SkScan::FillIRect(bounds, *fRC, blitter); 1419 return; 1420 } 1421 } 1422 1423 SkAutoBitmapShaderInstall install(bitmap, paint); 1424 const SkPaint& shaderPaint = install.paintWithShader(); 1425 1426 SkMatrix matrix; 1427 SkRect r; 1428 1429 // get a scalar version of our rect 1430 r.set(bounds); 1431 1432 // tell the shader our offset 1433 matrix.setTranslate(r.fLeft, r.fTop); 1434 shaderPaint.getShader()->setLocalMatrix(matrix); 1435 1436 SkDraw draw(*this); 1437 matrix.reset(); 1438 draw.fMatrix = &matrix; 1439 // call ourself with a rect 1440 // is this OK if paint has a rasterizer? 1441 draw.drawRect(r, shaderPaint); 1442} 1443 1444/////////////////////////////////////////////////////////////////////////////// 1445 1446#include "SkScalerContext.h" 1447#include "SkGlyphCache.h" 1448#include "SkTextToPathIter.h" 1449#include "SkUtils.h" 1450 1451static void measure_text(SkGlyphCache* cache, SkDrawCacheProc glyphCacheProc, 1452 const char text[], size_t byteLength, SkVector* stopVector) { 1453 SkFixed x = 0, y = 0; 1454 const char* stop = text + byteLength; 1455 1456 SkAutoKern autokern; 1457 1458 while (text < stop) { 1459 // don't need x, y here, since all subpixel variants will have the 1460 // same advance 1461 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); 1462 1463 x += autokern.adjust(glyph) + glyph.fAdvanceX; 1464 y += glyph.fAdvanceY; 1465 } 1466 stopVector->set(SkFixedToScalar(x), SkFixedToScalar(y)); 1467 1468 SkASSERT(text == stop); 1469} 1470 1471void SkDraw::drawText_asPaths(const char text[], size_t byteLength, 1472 SkScalar x, SkScalar y, 1473 const SkPaint& paint) const { 1474 SkDEBUGCODE(this->validate();) 1475 1476 SkTextToPathIter iter(text, byteLength, paint, true); 1477 1478 SkMatrix matrix; 1479 matrix.setScale(iter.getPathScale(), iter.getPathScale()); 1480 matrix.postTranslate(x, y); 1481 1482 const SkPath* iterPath; 1483 SkScalar xpos, prevXPos = 0; 1484 1485 while (iter.next(&iterPath, &xpos)) { 1486 matrix.postTranslate(xpos - prevXPos, 0); 1487 if (iterPath) { 1488 const SkPaint& pnt = iter.getPaint(); 1489 if (fDevice) { 1490 fDevice->drawPath(*this, *iterPath, pnt, &matrix, false); 1491 } else { 1492 this->drawPath(*iterPath, pnt, &matrix, false); 1493 } 1494 } 1495 prevXPos = xpos; 1496 } 1497} 1498 1499// disable warning : local variable used without having been initialized 1500#if defined _WIN32 && _MSC_VER >= 1300 1501#pragma warning ( push ) 1502#pragma warning ( disable : 4701 ) 1503#endif 1504 1505////////////////////////////////////////////////////////////////////////////// 1506 1507static void D1G_NoBounder_RectClip(const SkDraw1Glyph& state, 1508 SkFixed fx, SkFixed fy, 1509 const SkGlyph& glyph) { 1510 int left = SkFixedFloor(fx); 1511 int top = SkFixedFloor(fy); 1512 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0); 1513 SkASSERT(NULL == state.fBounder); 1514 SkASSERT((NULL == state.fClip && state.fAAClip) || 1515 (state.fClip && NULL == state.fAAClip && state.fClip->isRect())); 1516 1517 left += glyph.fLeft; 1518 top += glyph.fTop; 1519 1520 int right = left + glyph.fWidth; 1521 int bottom = top + glyph.fHeight; 1522 1523 SkMask mask; 1524 SkIRect storage; 1525 SkIRect* bounds = &mask.fBounds; 1526 1527 mask.fBounds.set(left, top, right, bottom); 1528 1529 // this extra test is worth it, assuming that most of the time it succeeds 1530 // since we can avoid writing to storage 1531 if (!state.fClipBounds.containsNoEmptyCheck(left, top, right, bottom)) { 1532 if (!storage.intersectNoEmptyCheck(mask.fBounds, state.fClipBounds)) 1533 return; 1534 bounds = &storage; 1535 } 1536 1537 uint8_t* aa = (uint8_t*)glyph.fImage; 1538 if (NULL == aa) { 1539 aa = (uint8_t*)state.fCache->findImage(glyph); 1540 if (NULL == aa) { 1541 return; // can't rasterize glyph 1542 } 1543 } 1544 1545 mask.fRowBytes = glyph.rowBytes(); 1546 mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat); 1547 mask.fImage = aa; 1548 state.blitMask(mask, *bounds); 1549} 1550 1551static void D1G_NoBounder_RgnClip(const SkDraw1Glyph& state, 1552 SkFixed fx, SkFixed fy, 1553 const SkGlyph& glyph) { 1554 int left = SkFixedFloor(fx); 1555 int top = SkFixedFloor(fy); 1556 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0); 1557 SkASSERT(!state.fClip->isRect()); 1558 SkASSERT(NULL == state.fBounder); 1559 1560 SkMask mask; 1561 1562 left += glyph.fLeft; 1563 top += glyph.fTop; 1564 1565 mask.fBounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight); 1566 SkRegion::Cliperator clipper(*state.fClip, mask.fBounds); 1567 1568 if (!clipper.done()) { 1569 const SkIRect& cr = clipper.rect(); 1570 const uint8_t* aa = (const uint8_t*)glyph.fImage; 1571 if (NULL == aa) { 1572 aa = (uint8_t*)state.fCache->findImage(glyph); 1573 if (NULL == aa) { 1574 return; 1575 } 1576 } 1577 1578 mask.fRowBytes = glyph.rowBytes(); 1579 mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat); 1580 mask.fImage = (uint8_t*)aa; 1581 do { 1582 state.blitMask(mask, cr); 1583 clipper.next(); 1584 } while (!clipper.done()); 1585 } 1586} 1587 1588static void D1G_Bounder(const SkDraw1Glyph& state, 1589 SkFixed fx, SkFixed fy, 1590 const SkGlyph& glyph) { 1591 int left = SkFixedFloor(fx); 1592 int top = SkFixedFloor(fy); 1593 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0); 1594 1595 SkMask mask; 1596 1597 left += glyph.fLeft; 1598 top += glyph.fTop; 1599 1600 mask.fBounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight); 1601 SkRegion::Cliperator clipper(*state.fClip, mask.fBounds); 1602 1603 if (!clipper.done()) { 1604 const SkIRect& cr = clipper.rect(); 1605 const uint8_t* aa = (const uint8_t*)glyph.fImage; 1606 if (NULL == aa) { 1607 aa = (uint8_t*)state.fCache->findImage(glyph); 1608 if (NULL == aa) { 1609 return; 1610 } 1611 } 1612 1613 // we need to pass the origin, which we approximate with our 1614 // (unadjusted) left,top coordinates (the caller called fixedfloor) 1615 if (state.fBounder->doIRectGlyph(cr, 1616 left - glyph.fLeft, 1617 top - glyph.fTop, glyph)) { 1618 mask.fRowBytes = glyph.rowBytes(); 1619 mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat); 1620 mask.fImage = (uint8_t*)aa; 1621 do { 1622 state.blitMask(mask, cr); 1623 clipper.next(); 1624 } while (!clipper.done()); 1625 } 1626 } 1627} 1628 1629static void D1G_Bounder_AAClip(const SkDraw1Glyph& state, 1630 SkFixed fx, SkFixed fy, 1631 const SkGlyph& glyph) { 1632 int left = SkFixedFloor(fx); 1633 int top = SkFixedFloor(fy); 1634 SkIRect bounds; 1635 bounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight); 1636 1637 if (state.fBounder->doIRectGlyph(bounds, left, top, glyph)) { 1638 D1G_NoBounder_RectClip(state, fx, fy, glyph); 1639 } 1640} 1641 1642static bool hasCustomD1GProc(const SkDraw& draw) { 1643 return draw.fProcs && draw.fProcs->fD1GProc; 1644} 1645 1646static bool needsRasterTextBlit(const SkDraw& draw) { 1647 return !hasCustomD1GProc(draw); 1648} 1649 1650SkDraw1Glyph::Proc SkDraw1Glyph::init(const SkDraw* draw, SkBlitter* blitter, 1651 SkGlyphCache* cache, const SkPaint& pnt) { 1652 fDraw = draw; 1653 fBounder = draw->fBounder; 1654 fBlitter = blitter; 1655 fCache = cache; 1656 fPaint = &pnt; 1657 1658 if (cache->isSubpixel()) { 1659 fHalfSampleX = fHalfSampleY = (SK_FixedHalf >> SkGlyph::kSubBits); 1660 } else { 1661 fHalfSampleX = fHalfSampleY = SK_FixedHalf; 1662 } 1663 1664 if (hasCustomD1GProc(*draw)) { 1665 // todo: fix this assumption about clips w/ custom 1666 fClip = draw->fClip; 1667 fClipBounds = fClip->getBounds(); 1668 return draw->fProcs->fD1GProc; 1669 } 1670 1671 if (draw->fRC->isBW()) { 1672 fAAClip = NULL; 1673 fClip = &draw->fRC->bwRgn(); 1674 fClipBounds = fClip->getBounds(); 1675 if (NULL == fBounder) { 1676 if (fClip->isRect()) { 1677 return D1G_NoBounder_RectClip; 1678 } else { 1679 return D1G_NoBounder_RgnClip; 1680 } 1681 } else { 1682 return D1G_Bounder; 1683 } 1684 } else { // aaclip 1685 fAAClip = &draw->fRC->aaRgn(); 1686 fClip = NULL; 1687 fClipBounds = fAAClip->getBounds(); 1688 if (NULL == fBounder) { 1689 return D1G_NoBounder_RectClip; 1690 } else { 1691 return D1G_Bounder_AAClip; 1692 } 1693 } 1694} 1695 1696void SkDraw1Glyph::blitMaskAsSprite(const SkMask& mask) const { 1697 SkASSERT(SkMask::kARGB32_Format == mask.fFormat); 1698 1699 SkBitmap bm; 1700 bm.setConfig(SkBitmap::kARGB_8888_Config, 1701 mask.fBounds.width(), mask.fBounds.height(), mask.fRowBytes); 1702 bm.setPixels((SkPMColor*)mask.fImage); 1703 1704 fDraw->drawSprite(bm, mask.fBounds.x(), mask.fBounds.y(), *fPaint); 1705} 1706 1707/////////////////////////////////////////////////////////////////////////////// 1708 1709void SkDraw::drawText(const char text[], size_t byteLength, 1710 SkScalar x, SkScalar y, const SkPaint& paint) const { 1711 SkASSERT(byteLength == 0 || text != NULL); 1712 1713 SkDEBUGCODE(this->validate();) 1714 1715 // nothing to draw 1716 if (text == NULL || byteLength == 0 || fRC->isEmpty()) { 1717 return; 1718 } 1719 1720 // SkScalarRec doesn't currently have a way of representing hairline stroke and 1721 // will fill if its frame-width is 0. 1722 if (ShouldDrawTextAsPaths(paint, *fMatrix)) { 1723 this->drawText_asPaths(text, byteLength, x, y, paint); 1724 return; 1725 } 1726 1727 SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc(); 1728 1729 SkAutoGlyphCache autoCache(paint, &fDevice->fLeakyProperties, fMatrix); 1730 SkGlyphCache* cache = autoCache.getCache(); 1731 1732 // transform our starting point 1733 { 1734 SkPoint loc; 1735 fMatrix->mapXY(x, y, &loc); 1736 x = loc.fX; 1737 y = loc.fY; 1738 } 1739 1740 // need to measure first 1741 if (paint.getTextAlign() != SkPaint::kLeft_Align) { 1742 SkVector stop; 1743 1744 measure_text(cache, glyphCacheProc, text, byteLength, &stop); 1745 1746 SkScalar stopX = stop.fX; 1747 SkScalar stopY = stop.fY; 1748 1749 if (paint.getTextAlign() == SkPaint::kCenter_Align) { 1750 stopX = SkScalarHalf(stopX); 1751 stopY = SkScalarHalf(stopY); 1752 } 1753 x -= stopX; 1754 y -= stopY; 1755 } 1756 1757 const char* stop = text + byteLength; 1758 1759 SkAAClipBlitter aaBlitter; 1760 SkAutoBlitterChoose blitterChooser; 1761 SkBlitter* blitter = NULL; 1762 if (needsRasterTextBlit(*this)) { 1763 blitterChooser.choose(*fBitmap, *fMatrix, paint); 1764 blitter = blitterChooser.get(); 1765 if (fRC->isAA()) { 1766 aaBlitter.init(blitter, &fRC->aaRgn()); 1767 blitter = &aaBlitter; 1768 } 1769 } 1770 1771 SkAutoKern autokern; 1772 SkDraw1Glyph d1g; 1773 SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache, paint); 1774 1775 SkFixed fxMask = ~0; 1776 SkFixed fyMask = ~0; 1777 if (cache->isSubpixel()) { 1778 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(*fMatrix); 1779 if (kX_SkAxisAlignment == baseline) { 1780 fyMask = 0; 1781 d1g.fHalfSampleY = SK_FixedHalf; 1782 } else if (kY_SkAxisAlignment == baseline) { 1783 fxMask = 0; 1784 d1g.fHalfSampleX = SK_FixedHalf; 1785 } 1786 } 1787 1788 SkFixed fx = SkScalarToFixed(x) + d1g.fHalfSampleX; 1789 SkFixed fy = SkScalarToFixed(y) + d1g.fHalfSampleY; 1790 1791 while (text < stop) { 1792 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask); 1793 1794 fx += autokern.adjust(glyph); 1795 1796 if (glyph.fWidth) { 1797 proc(d1g, fx, fy, glyph); 1798 } 1799 fx += glyph.fAdvanceX; 1800 fy += glyph.fAdvanceY; 1801 } 1802} 1803 1804// last parameter is interpreted as SkFixed [x, y] 1805// return the fixed position, which may be rounded or not by the caller 1806// e.g. subpixel doesn't round 1807typedef void (*AlignProc)(const SkPoint&, const SkGlyph&, SkIPoint*); 1808 1809static void leftAlignProc(const SkPoint& loc, const SkGlyph& glyph, 1810 SkIPoint* dst) { 1811 dst->set(SkScalarToFixed(loc.fX), SkScalarToFixed(loc.fY)); 1812} 1813 1814static void centerAlignProc(const SkPoint& loc, const SkGlyph& glyph, 1815 SkIPoint* dst) { 1816 dst->set(SkScalarToFixed(loc.fX) - (glyph.fAdvanceX >> 1), 1817 SkScalarToFixed(loc.fY) - (glyph.fAdvanceY >> 1)); 1818} 1819 1820static void rightAlignProc(const SkPoint& loc, const SkGlyph& glyph, 1821 SkIPoint* dst) { 1822 dst->set(SkScalarToFixed(loc.fX) - glyph.fAdvanceX, 1823 SkScalarToFixed(loc.fY) - glyph.fAdvanceY); 1824} 1825 1826static AlignProc pick_align_proc(SkPaint::Align align) { 1827 static const AlignProc gProcs[] = { 1828 leftAlignProc, centerAlignProc, rightAlignProc 1829 }; 1830 1831 SkASSERT((unsigned)align < SK_ARRAY_COUNT(gProcs)); 1832 1833 return gProcs[align]; 1834} 1835 1836class TextMapState { 1837public: 1838 mutable SkPoint fLoc; 1839 1840 TextMapState(const SkMatrix& matrix, SkScalar y) 1841 : fMatrix(matrix), fProc(matrix.getMapXYProc()), fY(y) {} 1842 1843 typedef void (*Proc)(const TextMapState&, const SkScalar pos[]); 1844 1845 Proc pickProc(int scalarsPerPosition); 1846 1847private: 1848 const SkMatrix& fMatrix; 1849 SkMatrix::MapXYProc fProc; 1850 SkScalar fY; // ignored by MapXYProc 1851 // these are only used by Only... procs 1852 SkScalar fScaleX, fTransX, fTransformedY; 1853 1854 static void MapXProc(const TextMapState& state, const SkScalar pos[]) { 1855 state.fProc(state.fMatrix, *pos, state.fY, &state.fLoc); 1856 } 1857 1858 static void MapXYProc(const TextMapState& state, const SkScalar pos[]) { 1859 state.fProc(state.fMatrix, pos[0], pos[1], &state.fLoc); 1860 } 1861 1862 static void MapOnlyScaleXProc(const TextMapState& state, 1863 const SkScalar pos[]) { 1864 state.fLoc.set(SkScalarMul(state.fScaleX, *pos) + state.fTransX, 1865 state.fTransformedY); 1866 } 1867 1868 static void MapOnlyTransXProc(const TextMapState& state, 1869 const SkScalar pos[]) { 1870 state.fLoc.set(*pos + state.fTransX, state.fTransformedY); 1871 } 1872}; 1873 1874TextMapState::Proc TextMapState::pickProc(int scalarsPerPosition) { 1875 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); 1876 1877 if (1 == scalarsPerPosition) { 1878 unsigned mtype = fMatrix.getType(); 1879 if (mtype & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)) { 1880 return MapXProc; 1881 } else { 1882 fScaleX = fMatrix.getScaleX(); 1883 fTransX = fMatrix.getTranslateX(); 1884 fTransformedY = SkScalarMul(fY, fMatrix.getScaleY()) + 1885 fMatrix.getTranslateY(); 1886 return (mtype & SkMatrix::kScale_Mask) ? 1887 MapOnlyScaleXProc : MapOnlyTransXProc; 1888 } 1889 } else { 1890 return MapXYProc; 1891 } 1892} 1893 1894////////////////////////////////////////////////////////////////////////////// 1895 1896void SkDraw::drawPosText_asPaths(const char text[], size_t byteLength, 1897 const SkScalar pos[], SkScalar constY, 1898 int scalarsPerPosition, 1899 const SkPaint& origPaint) const { 1900 // setup our std paint, in hopes of getting hits in the cache 1901 SkPaint paint(origPaint); 1902 SkScalar matrixScale = paint.setupForAsPaths(); 1903 1904 SkMatrix matrix; 1905 matrix.setScale(matrixScale, matrixScale); 1906 1907 SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc(); 1908 SkAutoGlyphCache autoCache(paint, NULL, NULL); 1909 SkGlyphCache* cache = autoCache.getCache(); 1910 1911 const char* stop = text + byteLength; 1912 AlignProc alignProc = pick_align_proc(paint.getTextAlign()); 1913 TextMapState tms(SkMatrix::I(), constY); 1914 TextMapState::Proc tmsProc = tms.pickProc(scalarsPerPosition); 1915 1916 while (text < stop) { 1917 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); 1918 if (glyph.fWidth) { 1919 const SkPath* path = cache->findPath(glyph); 1920 if (path) { 1921 tmsProc(tms, pos); 1922 SkIPoint fixedLoc; 1923 alignProc(tms.fLoc, glyph, &fixedLoc); 1924 1925 matrix[SkMatrix::kMTransX] = SkFixedToScalar(fixedLoc.fX); 1926 matrix[SkMatrix::kMTransY] = SkFixedToScalar(fixedLoc.fY); 1927 if (fDevice) { 1928 fDevice->drawPath(*this, *path, paint, &matrix, false); 1929 } else { 1930 this->drawPath(*path, paint, &matrix, false); 1931 } 1932 } 1933 } 1934 pos += scalarsPerPosition; 1935 } 1936} 1937 1938void SkDraw::drawPosText(const char text[], size_t byteLength, 1939 const SkScalar pos[], SkScalar constY, 1940 int scalarsPerPosition, const SkPaint& paint) const { 1941 SkASSERT(byteLength == 0 || text != NULL); 1942 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); 1943 1944 SkDEBUGCODE(this->validate();) 1945 1946 // nothing to draw 1947 if (text == NULL || byteLength == 0 || fRC->isEmpty()) { 1948 return; 1949 } 1950 1951 if (ShouldDrawTextAsPaths(paint, *fMatrix)) { 1952 this->drawPosText_asPaths(text, byteLength, pos, constY, 1953 scalarsPerPosition, paint); 1954 return; 1955 } 1956 1957 SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc(); 1958 SkAutoGlyphCache autoCache(paint, &fDevice->fLeakyProperties, fMatrix); 1959 SkGlyphCache* cache = autoCache.getCache(); 1960 1961 SkAAClipBlitterWrapper wrapper; 1962 SkAutoBlitterChoose blitterChooser; 1963 SkBlitter* blitter = NULL; 1964 if (needsRasterTextBlit(*this)) { 1965 blitterChooser.choose(*fBitmap, *fMatrix, paint); 1966 blitter = blitterChooser.get(); 1967 if (fRC->isAA()) { 1968 wrapper.init(*fRC, blitter); 1969 blitter = wrapper.getBlitter(); 1970 } 1971 } 1972 1973 const char* stop = text + byteLength; 1974 AlignProc alignProc = pick_align_proc(paint.getTextAlign()); 1975 SkDraw1Glyph d1g; 1976 SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache, paint); 1977 TextMapState tms(*fMatrix, constY); 1978 TextMapState::Proc tmsProc = tms.pickProc(scalarsPerPosition); 1979 1980 if (cache->isSubpixel()) { 1981 // maybe we should skip the rounding if linearText is set 1982 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(*fMatrix); 1983 1984 SkFixed fxMask = ~0; 1985 SkFixed fyMask = ~0; 1986 if (kX_SkAxisAlignment == baseline) { 1987 fyMask = 0; 1988#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX 1989 d1g.fHalfSampleY = SK_FixedHalf; 1990#endif 1991 } else if (kY_SkAxisAlignment == baseline) { 1992 fxMask = 0; 1993#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX 1994 d1g.fHalfSampleX = SK_FixedHalf; 1995#endif 1996 } 1997 1998 if (SkPaint::kLeft_Align == paint.getTextAlign()) { 1999 while (text < stop) { 2000 tmsProc(tms, pos); 2001 2002 SkFixed fx = SkScalarToFixed(tms.fLoc.fX) + d1g.fHalfSampleX; 2003 SkFixed fy = SkScalarToFixed(tms.fLoc.fY) + d1g.fHalfSampleY; 2004 2005 const SkGlyph& glyph = glyphCacheProc(cache, &text, 2006 fx & fxMask, fy & fyMask); 2007 2008 if (glyph.fWidth) { 2009 proc(d1g, fx, fy, glyph); 2010 } 2011 pos += scalarsPerPosition; 2012 } 2013 } else { 2014 while (text < stop) { 2015 const char* currentText = text; 2016 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0); 2017 2018 if (metricGlyph.fWidth) { 2019 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;) 2020 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;) 2021 2022 tmsProc(tms, pos); 2023 SkIPoint fixedLoc; 2024 alignProc(tms.fLoc, metricGlyph, &fixedLoc); 2025 2026 SkFixed fx = fixedLoc.fX + d1g.fHalfSampleX; 2027 SkFixed fy = fixedLoc.fY + d1g.fHalfSampleY; 2028 2029 // have to call again, now that we've been "aligned" 2030 const SkGlyph& glyph = glyphCacheProc(cache, ¤tText, 2031 fx & fxMask, fy & fyMask); 2032 // the assumption is that the metrics haven't changed 2033 SkASSERT(prevAdvX == glyph.fAdvanceX); 2034 SkASSERT(prevAdvY == glyph.fAdvanceY); 2035 SkASSERT(glyph.fWidth); 2036 2037 proc(d1g, fx, fy, glyph); 2038 } 2039 pos += scalarsPerPosition; 2040 } 2041 } 2042 } else { // not subpixel 2043 if (SkPaint::kLeft_Align == paint.getTextAlign()) { 2044 while (text < stop) { 2045 // the last 2 parameters are ignored 2046 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); 2047 2048 if (glyph.fWidth) { 2049 tmsProc(tms, pos); 2050 2051 proc(d1g, 2052 SkScalarToFixed(tms.fLoc.fX) + SK_FixedHalf, //d1g.fHalfSampleX, 2053 SkScalarToFixed(tms.fLoc.fY) + SK_FixedHalf, //d1g.fHalfSampleY, 2054 glyph); 2055 } 2056 pos += scalarsPerPosition; 2057 } 2058 } else { 2059 while (text < stop) { 2060 // the last 2 parameters are ignored 2061 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); 2062 2063 if (glyph.fWidth) { 2064 tmsProc(tms, pos); 2065 2066 SkIPoint fixedLoc; 2067 alignProc(tms.fLoc, glyph, &fixedLoc); 2068 2069 proc(d1g, 2070 fixedLoc.fX + SK_FixedHalf, //d1g.fHalfSampleX, 2071 fixedLoc.fY + SK_FixedHalf, //d1g.fHalfSampleY, 2072 glyph); 2073 } 2074 pos += scalarsPerPosition; 2075 } 2076 } 2077 } 2078} 2079 2080#if defined _WIN32 && _MSC_VER >= 1300 2081#pragma warning ( pop ) 2082#endif 2083 2084/////////////////////////////////////////////////////////////////////////////// 2085 2086#include "SkPathMeasure.h" 2087 2088static void morphpoints(SkPoint dst[], const SkPoint src[], int count, 2089 SkPathMeasure& meas, const SkMatrix& matrix) { 2090 SkMatrix::MapXYProc proc = matrix.getMapXYProc(); 2091 2092 for (int i = 0; i < count; i++) { 2093 SkPoint pos; 2094 SkVector tangent; 2095 2096 proc(matrix, src[i].fX, src[i].fY, &pos); 2097 SkScalar sx = pos.fX; 2098 SkScalar sy = pos.fY; 2099 2100 if (!meas.getPosTan(sx, &pos, &tangent)) { 2101 // set to 0 if the measure failed, so that we just set dst == pos 2102 tangent.set(0, 0); 2103 } 2104 2105 /* This is the old way (that explains our approach but is way too slow 2106 SkMatrix matrix; 2107 SkPoint pt; 2108 2109 pt.set(sx, sy); 2110 matrix.setSinCos(tangent.fY, tangent.fX); 2111 matrix.preTranslate(-sx, 0); 2112 matrix.postTranslate(pos.fX, pos.fY); 2113 matrix.mapPoints(&dst[i], &pt, 1); 2114 */ 2115 dst[i].set(pos.fX - SkScalarMul(tangent.fY, sy), 2116 pos.fY + SkScalarMul(tangent.fX, sy)); 2117 } 2118} 2119 2120/* TODO 2121 2122 Need differentially more subdivisions when the follow-path is curvy. Not sure how to 2123 determine that, but we need it. I guess a cheap answer is let the caller tell us, 2124 but that seems like a cop-out. Another answer is to get Rob Johnson to figure it out. 2125*/ 2126static void morphpath(SkPath* dst, const SkPath& src, SkPathMeasure& meas, 2127 const SkMatrix& matrix) { 2128 SkPath::Iter iter(src, false); 2129 SkPoint srcP[4], dstP[3]; 2130 SkPath::Verb verb; 2131 2132 while ((verb = iter.next(srcP)) != SkPath::kDone_Verb) { 2133 switch (verb) { 2134 case SkPath::kMove_Verb: 2135 morphpoints(dstP, srcP, 1, meas, matrix); 2136 dst->moveTo(dstP[0]); 2137 break; 2138 case SkPath::kLine_Verb: 2139 // turn lines into quads to look bendy 2140 srcP[0].fX = SkScalarAve(srcP[0].fX, srcP[1].fX); 2141 srcP[0].fY = SkScalarAve(srcP[0].fY, srcP[1].fY); 2142 morphpoints(dstP, srcP, 2, meas, matrix); 2143 dst->quadTo(dstP[0], dstP[1]); 2144 break; 2145 case SkPath::kQuad_Verb: 2146 morphpoints(dstP, &srcP[1], 2, meas, matrix); 2147 dst->quadTo(dstP[0], dstP[1]); 2148 break; 2149 case SkPath::kCubic_Verb: 2150 morphpoints(dstP, &srcP[1], 3, meas, matrix); 2151 dst->cubicTo(dstP[0], dstP[1], dstP[2]); 2152 break; 2153 case SkPath::kClose_Verb: 2154 dst->close(); 2155 break; 2156 default: 2157 SkDEBUGFAIL("unknown verb"); 2158 break; 2159 } 2160 } 2161} 2162 2163void SkDraw::drawTextOnPath(const char text[], size_t byteLength, 2164 const SkPath& follow, const SkMatrix* matrix, 2165 const SkPaint& paint) const { 2166 SkASSERT(byteLength == 0 || text != NULL); 2167 2168 // nothing to draw 2169 if (text == NULL || byteLength == 0 || fRC->isEmpty()) { 2170 return; 2171 } 2172 2173 SkTextToPathIter iter(text, byteLength, paint, true); 2174 SkPathMeasure meas(follow, false); 2175 SkScalar hOffset = 0; 2176 2177 // need to measure first 2178 if (paint.getTextAlign() != SkPaint::kLeft_Align) { 2179 SkScalar pathLen = meas.getLength(); 2180 if (paint.getTextAlign() == SkPaint::kCenter_Align) { 2181 pathLen = SkScalarHalf(pathLen); 2182 } 2183 hOffset += pathLen; 2184 } 2185 2186 const SkPath* iterPath; 2187 SkScalar xpos; 2188 SkMatrix scaledMatrix; 2189 SkScalar scale = iter.getPathScale(); 2190 2191 scaledMatrix.setScale(scale, scale); 2192 2193 while (iter.next(&iterPath, &xpos)) { 2194 if (iterPath) { 2195 SkPath tmp; 2196 SkMatrix m(scaledMatrix); 2197 2198 m.postTranslate(xpos + hOffset, 0); 2199 if (matrix) { 2200 m.postConcat(*matrix); 2201 } 2202 morphpath(&tmp, *iterPath, meas, m); 2203 if (fDevice) { 2204 fDevice->drawPath(*this, tmp, iter.getPaint(), NULL, true); 2205 } else { 2206 this->drawPath(tmp, iter.getPaint(), NULL, true); 2207 } 2208 } 2209 } 2210} 2211 2212#ifdef SK_BUILD_FOR_ANDROID 2213void SkDraw::drawPosTextOnPath(const char text[], size_t byteLength, 2214 const SkPoint pos[], const SkPaint& paint, 2215 const SkPath& path, const SkMatrix* matrix) const { 2216 // nothing to draw 2217 if (text == NULL || byteLength == 0 || fRC->isEmpty()) { 2218 return; 2219 } 2220 2221 SkMatrix scaledMatrix; 2222 SkPathMeasure meas(path, false); 2223 2224 SkMeasureCacheProc glyphCacheProc = paint.getMeasureCacheProc( 2225 SkPaint::kForward_TextBufferDirection, true); 2226 2227 // Copied (modified) from SkTextToPathIter constructor to setup paint 2228 SkPaint tempPaint(paint); 2229 2230 tempPaint.setLinearText(true); 2231 tempPaint.setMaskFilter(NULL); // don't want this affecting our path-cache lookup 2232 2233 if (tempPaint.getPathEffect() == NULL && !(tempPaint.getStrokeWidth() > 0 2234 && tempPaint.getStyle() != SkPaint::kFill_Style)) { 2235 tempPaint.setStyle(SkPaint::kFill_Style); 2236 tempPaint.setPathEffect(NULL); 2237 } 2238 // End copied from SkTextToPathIter constructor 2239 2240 // detach cache 2241 SkGlyphCache* cache = tempPaint.detachCache(NULL, NULL); 2242 2243 // Must set scale, even if 1 2244 SkScalar scale = SK_Scalar1; 2245 scaledMatrix.setScale(scale, scale); 2246 2247 // Loop over all glyph ids 2248 for (const char* stop = text + byteLength; text < stop; pos++) { 2249 2250 const SkGlyph& glyph = glyphCacheProc(cache, &text); 2251 SkPath tmp; 2252 2253 const SkPath* glyphPath = cache->findPath(glyph); 2254 if (glyphPath == NULL) { 2255 continue; 2256 } 2257 2258 SkMatrix m(scaledMatrix); 2259 m.postTranslate(pos->fX, 0); 2260 2261 if (matrix) { 2262 m.postConcat(*matrix); 2263 } 2264 2265 morphpath(&tmp, *glyphPath, meas, m); 2266 this->drawPath(tmp, tempPaint); 2267 2268 } 2269 2270 // re-attach cache 2271 SkGlyphCache::AttachCache(cache); 2272} 2273#endif 2274 2275/////////////////////////////////////////////////////////////////////////////// 2276 2277struct VertState { 2278 int f0, f1, f2; 2279 2280 VertState(int vCount, const uint16_t indices[], int indexCount) 2281 : fIndices(indices) { 2282 fCurrIndex = 0; 2283 if (indices) { 2284 fCount = indexCount; 2285 } else { 2286 fCount = vCount; 2287 } 2288 } 2289 2290 typedef bool (*Proc)(VertState*); 2291 Proc chooseProc(SkCanvas::VertexMode mode); 2292 2293private: 2294 int fCount; 2295 int fCurrIndex; 2296 const uint16_t* fIndices; 2297 2298 static bool Triangles(VertState*); 2299 static bool TrianglesX(VertState*); 2300 static bool TriangleStrip(VertState*); 2301 static bool TriangleStripX(VertState*); 2302 static bool TriangleFan(VertState*); 2303 static bool TriangleFanX(VertState*); 2304}; 2305 2306bool VertState::Triangles(VertState* state) { 2307 int index = state->fCurrIndex; 2308 if (index + 3 > state->fCount) { 2309 return false; 2310 } 2311 state->f0 = index + 0; 2312 state->f1 = index + 1; 2313 state->f2 = index + 2; 2314 state->fCurrIndex = index + 3; 2315 return true; 2316} 2317 2318bool VertState::TrianglesX(VertState* state) { 2319 const uint16_t* indices = state->fIndices; 2320 int index = state->fCurrIndex; 2321 if (index + 3 > state->fCount) { 2322 return false; 2323 } 2324 state->f0 = indices[index + 0]; 2325 state->f1 = indices[index + 1]; 2326 state->f2 = indices[index + 2]; 2327 state->fCurrIndex = index + 3; 2328 return true; 2329} 2330 2331bool VertState::TriangleStrip(VertState* state) { 2332 int index = state->fCurrIndex; 2333 if (index + 3 > state->fCount) { 2334 return false; 2335 } 2336 state->f2 = index + 2; 2337 if (index & 1) { 2338 state->f0 = index + 1; 2339 state->f1 = index + 0; 2340 } else { 2341 state->f0 = index + 0; 2342 state->f1 = index + 1; 2343 } 2344 state->fCurrIndex = index + 1; 2345 return true; 2346} 2347 2348bool VertState::TriangleStripX(VertState* state) { 2349 const uint16_t* indices = state->fIndices; 2350 int index = state->fCurrIndex; 2351 if (index + 3 > state->fCount) { 2352 return false; 2353 } 2354 state->f2 = indices[index + 2]; 2355 if (index & 1) { 2356 state->f0 = indices[index + 1]; 2357 state->f1 = indices[index + 0]; 2358 } else { 2359 state->f0 = indices[index + 0]; 2360 state->f1 = indices[index + 1]; 2361 } 2362 state->fCurrIndex = index + 1; 2363 return true; 2364} 2365 2366bool VertState::TriangleFan(VertState* state) { 2367 int index = state->fCurrIndex; 2368 if (index + 3 > state->fCount) { 2369 return false; 2370 } 2371 state->f0 = 0; 2372 state->f1 = index + 1; 2373 state->f2 = index + 2; 2374 state->fCurrIndex = index + 1; 2375 return true; 2376} 2377 2378bool VertState::TriangleFanX(VertState* state) { 2379 const uint16_t* indices = state->fIndices; 2380 int index = state->fCurrIndex; 2381 if (index + 3 > state->fCount) { 2382 return false; 2383 } 2384 state->f0 = indices[0]; 2385 state->f1 = indices[index + 1]; 2386 state->f2 = indices[index + 2]; 2387 state->fCurrIndex = index + 1; 2388 return true; 2389} 2390 2391VertState::Proc VertState::chooseProc(SkCanvas::VertexMode mode) { 2392 switch (mode) { 2393 case SkCanvas::kTriangles_VertexMode: 2394 return fIndices ? TrianglesX : Triangles; 2395 case SkCanvas::kTriangleStrip_VertexMode: 2396 return fIndices ? TriangleStripX : TriangleStrip; 2397 case SkCanvas::kTriangleFan_VertexMode: 2398 return fIndices ? TriangleFanX : TriangleFan; 2399 default: 2400 return NULL; 2401 } 2402} 2403 2404typedef void (*HairProc)(const SkPoint&, const SkPoint&, const SkRasterClip&, 2405 SkBlitter*); 2406 2407static HairProc ChooseHairProc(bool doAntiAlias) { 2408 return doAntiAlias ? SkScan::AntiHairLine : SkScan::HairLine; 2409} 2410 2411static bool texture_to_matrix(const VertState& state, const SkPoint verts[], 2412 const SkPoint texs[], SkMatrix* matrix) { 2413 SkPoint src[3], dst[3]; 2414 2415 src[0] = texs[state.f0]; 2416 src[1] = texs[state.f1]; 2417 src[2] = texs[state.f2]; 2418 dst[0] = verts[state.f0]; 2419 dst[1] = verts[state.f1]; 2420 dst[2] = verts[state.f2]; 2421 return matrix->setPolyToPoly(src, dst, 3); 2422} 2423 2424class SkTriColorShader : public SkShader { 2425public: 2426 SkTriColorShader() {} 2427 2428 bool setup(const SkPoint pts[], const SkColor colors[], int, int, int); 2429 2430 virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE; 2431 2432 SK_DEVELOPER_TO_STRING() 2433 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTriColorShader) 2434 2435protected: 2436 SkTriColorShader(SkFlattenableReadBuffer& buffer) : SkShader(buffer) {} 2437 2438private: 2439 SkMatrix fDstToUnit; 2440 SkPMColor fColors[3]; 2441 2442 typedef SkShader INHERITED; 2443}; 2444 2445bool SkTriColorShader::setup(const SkPoint pts[], const SkColor colors[], 2446 int index0, int index1, int index2) { 2447 2448 fColors[0] = SkPreMultiplyColor(colors[index0]); 2449 fColors[1] = SkPreMultiplyColor(colors[index1]); 2450 fColors[2] = SkPreMultiplyColor(colors[index2]); 2451 2452 SkMatrix m, im; 2453 m.reset(); 2454 m.set(0, pts[index1].fX - pts[index0].fX); 2455 m.set(1, pts[index2].fX - pts[index0].fX); 2456 m.set(2, pts[index0].fX); 2457 m.set(3, pts[index1].fY - pts[index0].fY); 2458 m.set(4, pts[index2].fY - pts[index0].fY); 2459 m.set(5, pts[index0].fY); 2460 if (!m.invert(&im)) { 2461 return false; 2462 } 2463 return fDstToUnit.setConcat(im, this->getTotalInverse()); 2464} 2465 2466#include "SkColorPriv.h" 2467#include "SkComposeShader.h" 2468 2469static int ScalarTo256(SkScalar v) { 2470 int scale = SkScalarToFixed(v) >> 8; 2471 if (scale < 0) { 2472 scale = 0; 2473 } 2474 if (scale > 255) { 2475 scale = 255; 2476 } 2477 return SkAlpha255To256(scale); 2478} 2479 2480void SkTriColorShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) { 2481 SkPoint src; 2482 2483 for (int i = 0; i < count; i++) { 2484 fDstToUnit.mapXY(SkIntToScalar(x), SkIntToScalar(y), &src); 2485 x += 1; 2486 2487 int scale1 = ScalarTo256(src.fX); 2488 int scale2 = ScalarTo256(src.fY); 2489 int scale0 = 256 - scale1 - scale2; 2490 if (scale0 < 0) { 2491 if (scale1 > scale2) { 2492 scale2 = 256 - scale1; 2493 } else { 2494 scale1 = 256 - scale2; 2495 } 2496 scale0 = 0; 2497 } 2498 2499 dstC[i] = SkAlphaMulQ(fColors[0], scale0) + 2500 SkAlphaMulQ(fColors[1], scale1) + 2501 SkAlphaMulQ(fColors[2], scale2); 2502 } 2503} 2504 2505#ifdef SK_DEVELOPER 2506void SkTriColorShader::toString(SkString* str) const { 2507 str->append("SkTriColorShader: ("); 2508 2509 this->INHERITED::toString(str); 2510 2511 str->append(")"); 2512} 2513#endif 2514 2515void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count, 2516 const SkPoint vertices[], const SkPoint textures[], 2517 const SkColor colors[], SkXfermode* xmode, 2518 const uint16_t indices[], int indexCount, 2519 const SkPaint& paint) const { 2520 SkASSERT(0 == count || NULL != vertices); 2521 2522 // abort early if there is nothing to draw 2523 if (count < 3 || (indices && indexCount < 3) || fRC->isEmpty()) { 2524 return; 2525 } 2526 2527 // transform out vertices into device coordinates 2528 SkAutoSTMalloc<16, SkPoint> storage(count); 2529 SkPoint* devVerts = storage.get(); 2530 fMatrix->mapPoints(devVerts, vertices, count); 2531 2532 if (fBounder) { 2533 SkRect bounds; 2534 bounds.set(devVerts, count); 2535 if (!fBounder->doRect(bounds, paint)) { 2536 return; 2537 } 2538 } 2539 2540 /* 2541 We can draw the vertices in 1 of 4 ways: 2542 2543 - solid color (no shader/texture[], no colors[]) 2544 - just colors (no shader/texture[], has colors[]) 2545 - just texture (has shader/texture[], no colors[]) 2546 - colors * texture (has shader/texture[], has colors[]) 2547 2548 Thus for texture drawing, we need both texture[] and a shader. 2549 */ 2550 2551 SkTriColorShader triShader; // must be above declaration of p 2552 SkPaint p(paint); 2553 2554 SkShader* shader = p.getShader(); 2555 if (NULL == shader) { 2556 // if we have no shader, we ignore the texture coordinates 2557 textures = NULL; 2558 } else if (NULL == textures) { 2559 // if we don't have texture coordinates, ignore the shader 2560 p.setShader(NULL); 2561 shader = NULL; 2562 } 2563 2564 // setup the custom shader (if needed) 2565 if (NULL != colors) { 2566 if (NULL == textures) { 2567 // just colors (no texture) 2568 shader = p.setShader(&triShader); 2569 } else { 2570 // colors * texture 2571 SkASSERT(shader); 2572 bool releaseMode = false; 2573 if (NULL == xmode) { 2574 xmode = SkXfermode::Create(SkXfermode::kModulate_Mode); 2575 releaseMode = true; 2576 } 2577 SkShader* compose = SkNEW_ARGS(SkComposeShader, 2578 (&triShader, shader, xmode)); 2579 p.setShader(compose)->unref(); 2580 if (releaseMode) { 2581 xmode->unref(); 2582 } 2583 shader = compose; 2584 } 2585 } 2586 2587 SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, p); 2588 // important that we abort early, as below we may manipulate the shader 2589 // and that is only valid if the shader returned true from setContext. 2590 // If it returned false, then our blitter will be the NullBlitter. 2591 if (blitter->isNullBlitter()) { 2592 return; 2593 } 2594 2595 // setup our state and function pointer for iterating triangles 2596 VertState state(count, indices, indexCount); 2597 VertState::Proc vertProc = state.chooseProc(vmode); 2598 2599 if (NULL != textures || NULL != colors) { 2600 SkMatrix tempM; 2601 SkMatrix savedLocalM; 2602 if (shader) { 2603 savedLocalM = shader->getLocalMatrix(); 2604 } 2605 2606 // setContext has already been called and verified to return true 2607 // by the constructor of SkAutoBlitterChoose 2608 bool prevContextSuccess = true; 2609 while (vertProc(&state)) { 2610 if (NULL != textures) { 2611 if (texture_to_matrix(state, vertices, textures, &tempM)) { 2612 tempM.postConcat(savedLocalM); 2613 shader->setLocalMatrix(tempM); 2614 // Need to recall setContext since we changed the local matrix. 2615 // However, we also need to balance the calls this with a 2616 // call to endContext which requires tracking the result of 2617 // the previous call to setContext. 2618 if (prevContextSuccess) { 2619 shader->endContext(); 2620 } 2621 prevContextSuccess = shader->setContext(*fBitmap, p, *fMatrix); 2622 if (!prevContextSuccess) { 2623 continue; 2624 } 2625 } 2626 } 2627 if (NULL != colors) { 2628 if (!triShader.setup(vertices, colors, 2629 state.f0, state.f1, state.f2)) { 2630 continue; 2631 } 2632 } 2633 2634 SkPoint tmp[] = { 2635 devVerts[state.f0], devVerts[state.f1], devVerts[state.f2] 2636 }; 2637 SkScan::FillTriangle(tmp, *fRC, blitter.get()); 2638 } 2639 2640 // now restore the shader's original local matrix 2641 if (NULL != shader) { 2642 shader->setLocalMatrix(savedLocalM); 2643 } 2644 2645 // If the final call to setContext fails we must make it suceed so that the 2646 // call to endContext in the destructor for SkAutoBlitterChoose is balanced. 2647 if (!prevContextSuccess) { 2648 prevContextSuccess = shader->setContext(*fBitmap, paint, SkMatrix::I()); 2649 SkASSERT(prevContextSuccess); 2650 } 2651 } else { 2652 // no colors[] and no texture 2653 HairProc hairProc = ChooseHairProc(paint.isAntiAlias()); 2654 const SkRasterClip& clip = *fRC; 2655 while (vertProc(&state)) { 2656 hairProc(devVerts[state.f0], devVerts[state.f1], clip, blitter.get()); 2657 hairProc(devVerts[state.f1], devVerts[state.f2], clip, blitter.get()); 2658 hairProc(devVerts[state.f2], devVerts[state.f0], clip, blitter.get()); 2659 } 2660 } 2661} 2662 2663/////////////////////////////////////////////////////////////////////////////// 2664/////////////////////////////////////////////////////////////////////////////// 2665 2666#ifdef SK_DEBUG 2667 2668void SkDraw::validate() const { 2669 SkASSERT(fBitmap != NULL); 2670 SkASSERT(fMatrix != NULL); 2671 SkASSERT(fClip != NULL); 2672 SkASSERT(fRC != NULL); 2673 2674 const SkIRect& cr = fRC->getBounds(); 2675 SkIRect br; 2676 2677 br.set(0, 0, fBitmap->width(), fBitmap->height()); 2678 SkASSERT(cr.isEmpty() || br.contains(cr)); 2679} 2680 2681#endif 2682 2683/////////////////////////////////////////////////////////////////////////////// 2684 2685SkBounder::SkBounder() { 2686 // initialize up front. This gets reset by SkCanvas before each draw call. 2687 fClip = &SkRegion::GetEmptyRegion(); 2688} 2689 2690bool SkBounder::doIRect(const SkIRect& r) { 2691 SkIRect rr; 2692 return rr.intersect(fClip->getBounds(), r) && this->onIRect(rr); 2693} 2694 2695// TODO: change the prototype to take fixed, and update the callers 2696bool SkBounder::doIRectGlyph(const SkIRect& r, int x, int y, 2697 const SkGlyph& glyph) { 2698 SkIRect rr; 2699 if (!rr.intersect(fClip->getBounds(), r)) { 2700 return false; 2701 } 2702 GlyphRec rec; 2703 rec.fLSB.set(SkIntToFixed(x), SkIntToFixed(y)); 2704 rec.fRSB.set(rec.fLSB.fX + glyph.fAdvanceX, 2705 rec.fLSB.fY + glyph.fAdvanceY); 2706 rec.fGlyphID = glyph.getGlyphID(); 2707 rec.fFlags = 0; 2708 return this->onIRectGlyph(rr, rec); 2709} 2710 2711bool SkBounder::doHairline(const SkPoint& pt0, const SkPoint& pt1, 2712 const SkPaint& paint) { 2713 SkIRect r; 2714 SkScalar v0, v1; 2715 2716 v0 = pt0.fX; 2717 v1 = pt1.fX; 2718 if (v0 > v1) { 2719 SkTSwap<SkScalar>(v0, v1); 2720 } 2721 r.fLeft = SkScalarFloor(v0); 2722 r.fRight = SkScalarCeil(v1); 2723 2724 v0 = pt0.fY; 2725 v1 = pt1.fY; 2726 if (v0 > v1) { 2727 SkTSwap<SkScalar>(v0, v1); 2728 } 2729 r.fTop = SkScalarFloor(v0); 2730 r.fBottom = SkScalarCeil(v1); 2731 2732 if (paint.isAntiAlias()) { 2733 r.inset(-1, -1); 2734 } 2735 return this->doIRect(r); 2736} 2737 2738bool SkBounder::doRect(const SkRect& rect, const SkPaint& paint) { 2739 SkIRect r; 2740 2741 if (paint.getStyle() == SkPaint::kFill_Style) { 2742 rect.round(&r); 2743 } else { 2744 int rad = -1; 2745 rect.roundOut(&r); 2746 if (paint.isAntiAlias()) { 2747 rad = -2; 2748 } 2749 r.inset(rad, rad); 2750 } 2751 return this->doIRect(r); 2752} 2753 2754bool SkBounder::doPath(const SkPath& path, const SkPaint& paint, bool doFill) { 2755 SkIRect r; 2756 const SkRect& bounds = path.getBounds(); 2757 2758 if (doFill) { 2759 bounds.round(&r); 2760 } else { // hairline 2761 bounds.roundOut(&r); 2762 } 2763 2764 if (paint.isAntiAlias()) { 2765 r.inset(-1, -1); 2766 } 2767 return this->doIRect(r); 2768} 2769 2770void SkBounder::commit() { 2771 // override in subclass 2772} 2773 2774//////////////////////////////////////////////////////////////////////////////////////////////// 2775 2776#include "SkPath.h" 2777#include "SkDraw.h" 2778#include "SkRegion.h" 2779#include "SkBlitter.h" 2780 2781static bool compute_bounds(const SkPath& devPath, const SkIRect* clipBounds, 2782 const SkMaskFilter* filter, const SkMatrix* filterMatrix, 2783 SkIRect* bounds) { 2784 if (devPath.isEmpty()) { 2785 return false; 2786 } 2787 2788 // init our bounds from the path 2789 { 2790 SkRect pathBounds = devPath.getBounds(); 2791 pathBounds.inset(-SK_ScalarHalf, -SK_ScalarHalf); 2792 pathBounds.roundOut(bounds); 2793 } 2794 2795 SkIPoint margin = SkIPoint::Make(0, 0); 2796 if (filter) { 2797 SkASSERT(filterMatrix); 2798 2799 SkMask srcM, dstM; 2800 2801 srcM.fBounds = *bounds; 2802 srcM.fFormat = SkMask::kA8_Format; 2803 srcM.fImage = NULL; 2804 if (!filter->filterMask(&dstM, srcM, *filterMatrix, &margin)) { 2805 return false; 2806 } 2807 } 2808 2809 // (possibly) trim the bounds to reflect the clip 2810 // (plus whatever slop the filter needs) 2811 if (clipBounds) { 2812 SkIRect tmp = *clipBounds; 2813 // Ugh. Guard against gigantic margins from wacky filters. Without this 2814 // check we can request arbitrary amounts of slop beyond our visible 2815 // clip, and bring down the renderer (at least on finite RAM machines 2816 // like handsets, etc.). Need to balance this invented value between 2817 // quality of large filters like blurs, and the corresponding memory 2818 // requests. 2819 static const int MAX_MARGIN = 128; 2820 tmp.inset(-SkMin32(margin.fX, MAX_MARGIN), 2821 -SkMin32(margin.fY, MAX_MARGIN)); 2822 if (!bounds->intersect(tmp)) { 2823 return false; 2824 } 2825 } 2826 2827 return true; 2828} 2829 2830static void draw_into_mask(const SkMask& mask, const SkPath& devPath, 2831 SkPaint::Style style) { 2832 SkBitmap bm; 2833 SkDraw draw; 2834 SkRasterClip clip; 2835 SkMatrix matrix; 2836 SkPaint paint; 2837 2838 bm.setConfig(SkBitmap::kA8_Config, mask.fBounds.width(), mask.fBounds.height(), mask.fRowBytes); 2839 bm.setPixels(mask.fImage); 2840 2841 clip.setRect(SkIRect::MakeWH(mask.fBounds.width(), mask.fBounds.height())); 2842 matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft), 2843 -SkIntToScalar(mask.fBounds.fTop)); 2844 2845 draw.fBitmap = &bm; 2846 draw.fRC = &clip; 2847 draw.fClip = &clip.bwRgn(); 2848 draw.fMatrix = &matrix; 2849 draw.fBounder = NULL; 2850 paint.setAntiAlias(true); 2851 paint.setStyle(style); 2852 draw.drawPath(devPath, paint); 2853} 2854 2855bool SkDraw::DrawToMask(const SkPath& devPath, const SkIRect* clipBounds, 2856 const SkMaskFilter* filter, const SkMatrix* filterMatrix, 2857 SkMask* mask, SkMask::CreateMode mode, 2858 SkPaint::Style style) { 2859 if (SkMask::kJustRenderImage_CreateMode != mode) { 2860 if (!compute_bounds(devPath, clipBounds, filter, filterMatrix, &mask->fBounds)) 2861 return false; 2862 } 2863 2864 if (SkMask::kComputeBoundsAndRenderImage_CreateMode == mode) { 2865 mask->fFormat = SkMask::kA8_Format; 2866 mask->fRowBytes = mask->fBounds.width(); 2867 size_t size = mask->computeImageSize(); 2868 if (0 == size) { 2869 // we're too big to allocate the mask, abort 2870 return false; 2871 } 2872 mask->fImage = SkMask::AllocImage(size); 2873 memset(mask->fImage, 0, mask->computeImageSize()); 2874 } 2875 2876 if (SkMask::kJustComputeBounds_CreateMode != mode) { 2877 draw_into_mask(*mask, devPath, style); 2878 } 2879 2880 return true; 2881} 2882 2883