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