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