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