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