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