SkDraw.cpp revision e5f48243bdbed2662be7a31be0888abc273b09e8
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 size_t rb = bitmap->rowBytes(); 358 359 for (int i = 0; i < count; i++) { 360 int x = SkScalarFloorToInt(devPts[i].fX); 361 int y = SkScalarFloorToInt(devPts[i].fY); 362 if (r.contains(x, y)) { 363 ((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 size_t 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 unsigned bits = 0; // TODO: find a way to allow the caller to tell us to 1144 // respect filtering. 1145 return SkTreatAsSprite(matrix, bitmap.width(), bitmap.height(), bits); 1146} 1147 1148void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap, 1149 const SkPaint& paint) const { 1150 SkASSERT(bitmap.getConfig() == SkBitmap::kA8_Config); 1151 1152 if (just_translate(*fMatrix, bitmap)) { 1153 int ix = SkScalarRound(fMatrix->getTranslateX()); 1154 int iy = SkScalarRound(fMatrix->getTranslateY()); 1155 1156 SkAutoLockPixels alp(bitmap); 1157 if (!bitmap.readyToDraw()) { 1158 return; 1159 } 1160 1161 SkMask mask; 1162 mask.fBounds.set(ix, iy, ix + bitmap.width(), iy + bitmap.height()); 1163 mask.fFormat = SkMask::kA8_Format; 1164 mask.fRowBytes = SkToU32(bitmap.rowBytes()); 1165 mask.fImage = bitmap.getAddr8(0, 0); 1166 1167 this->drawDevMask(mask, paint); 1168 } else { // need to xform the bitmap first 1169 SkRect r; 1170 SkMask mask; 1171 1172 r.set(0, 0, 1173 SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height())); 1174 fMatrix->mapRect(&r); 1175 r.round(&mask.fBounds); 1176 1177 // set the mask's bounds to the transformed bitmap-bounds, 1178 // clipped to the actual device 1179 { 1180 SkIRect devBounds; 1181 devBounds.set(0, 0, fBitmap->width(), fBitmap->height()); 1182 // need intersect(l, t, r, b) on irect 1183 if (!mask.fBounds.intersect(devBounds)) { 1184 return; 1185 } 1186 } 1187 1188 mask.fFormat = SkMask::kA8_Format; 1189 mask.fRowBytes = SkAlign4(mask.fBounds.width()); 1190 size_t size = mask.computeImageSize(); 1191 if (0 == size) { 1192 // the mask is too big to allocated, draw nothing 1193 return; 1194 } 1195 1196 // allocate (and clear) our temp buffer to hold the transformed bitmap 1197 SkAutoMalloc storage(size); 1198 mask.fImage = (uint8_t*)storage.get(); 1199 memset(mask.fImage, 0, size); 1200 1201 // now draw our bitmap(src) into mask(dst), transformed by the matrix 1202 { 1203 SkBitmap device; 1204 device.setConfig(SkBitmap::kA8_Config, mask.fBounds.width(), 1205 mask.fBounds.height(), mask.fRowBytes); 1206 device.setPixels(mask.fImage); 1207 1208 SkCanvas c(device); 1209 // need the unclipped top/left for the translate 1210 c.translate(-SkIntToScalar(mask.fBounds.fLeft), 1211 -SkIntToScalar(mask.fBounds.fTop)); 1212 c.concat(*fMatrix); 1213 1214 // We can't call drawBitmap, or we'll infinitely recurse. Instead 1215 // we manually build a shader and draw that into our new mask 1216 SkPaint tmpPaint; 1217 tmpPaint.setFlags(paint.getFlags()); 1218 SkAutoBitmapShaderInstall install(bitmap, tmpPaint); 1219 SkRect rr; 1220 rr.set(0, 0, SkIntToScalar(bitmap.width()), 1221 SkIntToScalar(bitmap.height())); 1222 c.drawRect(rr, install.paintWithShader()); 1223 } 1224 this->drawDevMask(mask, paint); 1225 } 1226} 1227 1228static bool clipped_out(const SkMatrix& m, const SkRasterClip& c, 1229 const SkRect& srcR) { 1230 SkRect dstR; 1231 SkIRect devIR; 1232 1233 m.mapRect(&dstR, srcR); 1234 dstR.roundOut(&devIR); 1235 return c.quickReject(devIR); 1236} 1237 1238static bool clipped_out(const SkMatrix& matrix, const SkRasterClip& clip, 1239 int width, int height) { 1240 SkRect r; 1241 r.set(0, 0, SkIntToScalar(width), SkIntToScalar(height)); 1242 return clipped_out(matrix, clip, r); 1243} 1244 1245static bool clipHandlesSprite(const SkRasterClip& clip, int x, int y, 1246 const SkBitmap& bitmap) { 1247 return clip.isBW() || 1248 clip.quickContains(x, y, x + bitmap.width(), y + bitmap.height()); 1249} 1250 1251void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix, 1252 const SkPaint& origPaint) const { 1253 SkDEBUGCODE(this->validate();) 1254 1255 // nothing to draw 1256 if (fRC->isEmpty() || 1257 bitmap.width() == 0 || bitmap.height() == 0 || 1258 bitmap.getConfig() == SkBitmap::kNo_Config) { 1259 return; 1260 } 1261 1262#ifndef SK_ALLOW_OVER_32K_BITMAPS 1263 // run away on too-big bitmaps for now (exceed 16.16) 1264 if (bitmap.width() > 32767 || bitmap.height() > 32767) { 1265 return; 1266 } 1267#endif 1268 1269 SkPaint paint(origPaint); 1270 paint.setStyle(SkPaint::kFill_Style); 1271 1272 SkMatrix matrix; 1273 if (!matrix.setConcat(*fMatrix, prematrix)) { 1274 return; 1275 } 1276 1277 if (clipped_out(matrix, *fRC, bitmap.width(), bitmap.height())) { 1278 return; 1279 } 1280 1281 if (fBounder && just_translate(matrix, bitmap)) { 1282 SkIRect ir; 1283 int32_t ix = SkScalarRound(matrix.getTranslateX()); 1284 int32_t iy = SkScalarRound(matrix.getTranslateY()); 1285 ir.set(ix, iy, ix + bitmap.width(), iy + bitmap.height()); 1286 if (!fBounder->doIRect(ir)) { 1287 return; 1288 } 1289 } 1290 1291 if (bitmap.getConfig() != SkBitmap::kA8_Config && 1292 just_translate(matrix, bitmap)) { 1293 // 1294 // It is safe to call lock pixels now, since we know the matrix is 1295 // (more or less) identity. 1296 // 1297 SkAutoLockPixels alp(bitmap); 1298 if (!bitmap.readyToDraw()) { 1299 return; 1300 } 1301 int ix = SkScalarRound(matrix.getTranslateX()); 1302 int iy = SkScalarRound(matrix.getTranslateY()); 1303 if (clipHandlesSprite(*fRC, ix, iy, bitmap)) { 1304 uint32_t storage[kBlitterStorageLongCount]; 1305 SkBlitter* blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap, 1306 ix, iy, storage, sizeof(storage)); 1307 if (blitter) { 1308 SkAutoTPlacementDelete<SkBlitter> ad(blitter, storage); 1309 1310 SkIRect ir; 1311 ir.set(ix, iy, ix + bitmap.width(), iy + bitmap.height()); 1312 1313 SkScan::FillIRect(ir, *fRC, blitter); 1314 return; 1315 } 1316 } 1317 } 1318 1319 // now make a temp draw on the stack, and use it 1320 // 1321 SkDraw draw(*this); 1322 draw.fMatrix = &matrix; 1323 1324 if (bitmap.getConfig() == SkBitmap::kA8_Config) { 1325 draw.drawBitmapAsMask(bitmap, paint); 1326 } else { 1327 SkAutoBitmapShaderInstall install(bitmap, paint); 1328 1329 SkRect r; 1330 r.set(0, 0, SkIntToScalar(bitmap.width()), 1331 SkIntToScalar(bitmap.height())); 1332 // is this ok if paint has a rasterizer? 1333 draw.drawRect(r, install.paintWithShader()); 1334 } 1335} 1336 1337void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y, 1338 const SkPaint& origPaint) const { 1339 SkDEBUGCODE(this->validate();) 1340 1341 // nothing to draw 1342 if (fRC->isEmpty() || 1343 bitmap.width() == 0 || bitmap.height() == 0 || 1344 bitmap.getConfig() == SkBitmap::kNo_Config) { 1345 return; 1346 } 1347 1348 SkIRect bounds; 1349 bounds.set(x, y, x + bitmap.width(), y + bitmap.height()); 1350 1351 if (fRC->quickReject(bounds)) { 1352 return; // nothing to draw 1353 } 1354 1355 SkPaint paint(origPaint); 1356 paint.setStyle(SkPaint::kFill_Style); 1357 1358 if (NULL == paint.getColorFilter() && clipHandlesSprite(*fRC, x, y, bitmap)) { 1359 uint32_t storage[kBlitterStorageLongCount]; 1360 SkBlitter* blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap, 1361 x, y, storage, sizeof(storage)); 1362 1363 if (blitter) { 1364 SkAutoTPlacementDelete<SkBlitter> ad(blitter, storage); 1365 1366 if (fBounder && !fBounder->doIRect(bounds)) { 1367 return; 1368 } 1369 1370 SkScan::FillIRect(bounds, *fRC, blitter); 1371 return; 1372 } 1373 } 1374 1375 SkAutoBitmapShaderInstall install(bitmap, paint); 1376 const SkPaint& shaderPaint = install.paintWithShader(); 1377 1378 SkMatrix matrix; 1379 SkRect r; 1380 1381 // get a scalar version of our rect 1382 r.set(bounds); 1383 1384 // tell the shader our offset 1385 matrix.setTranslate(r.fLeft, r.fTop); 1386 shaderPaint.getShader()->setLocalMatrix(matrix); 1387 1388 SkDraw draw(*this); 1389 matrix.reset(); 1390 draw.fMatrix = &matrix; 1391 // call ourself with a rect 1392 // is this OK if paint has a rasterizer? 1393 draw.drawRect(r, shaderPaint); 1394} 1395 1396/////////////////////////////////////////////////////////////////////////////// 1397 1398#include "SkScalerContext.h" 1399#include "SkGlyphCache.h" 1400#include "SkTextToPathIter.h" 1401#include "SkUtils.h" 1402 1403static void measure_text(SkGlyphCache* cache, SkDrawCacheProc glyphCacheProc, 1404 const char text[], size_t byteLength, SkVector* stopVector) { 1405 SkFixed x = 0, y = 0; 1406 const char* stop = text + byteLength; 1407 1408 SkAutoKern autokern; 1409 1410 while (text < stop) { 1411 // don't need x, y here, since all subpixel variants will have the 1412 // same advance 1413 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); 1414 1415 x += autokern.adjust(glyph) + glyph.fAdvanceX; 1416 y += glyph.fAdvanceY; 1417 } 1418 stopVector->set(SkFixedToScalar(x), SkFixedToScalar(y)); 1419 1420 SkASSERT(text == stop); 1421} 1422 1423void SkDraw::drawText_asPaths(const char text[], size_t byteLength, 1424 SkScalar x, SkScalar y, 1425 const SkPaint& paint) const { 1426 SkDEBUGCODE(this->validate();) 1427 1428 SkTextToPathIter iter(text, byteLength, paint, true); 1429 1430 SkMatrix matrix; 1431 matrix.setScale(iter.getPathScale(), iter.getPathScale()); 1432 matrix.postTranslate(x, y); 1433 1434 const SkPath* iterPath; 1435 SkScalar xpos, prevXPos = 0; 1436 1437 while (iter.next(&iterPath, &xpos)) { 1438 matrix.postTranslate(xpos - prevXPos, 0); 1439 if (iterPath) { 1440 const SkPaint& pnt = iter.getPaint(); 1441 if (fDevice) { 1442 fDevice->drawPath(*this, *iterPath, pnt, &matrix, false); 1443 } else { 1444 this->drawPath(*iterPath, pnt, &matrix, false); 1445 } 1446 } 1447 prevXPos = xpos; 1448 } 1449} 1450 1451// disable warning : local variable used without having been initialized 1452#if defined _WIN32 && _MSC_VER >= 1300 1453#pragma warning ( push ) 1454#pragma warning ( disable : 4701 ) 1455#endif 1456 1457////////////////////////////////////////////////////////////////////////////// 1458 1459static void D1G_NoBounder_RectClip(const SkDraw1Glyph& state, 1460 SkFixed fx, SkFixed fy, 1461 const SkGlyph& glyph) { 1462 int left = SkFixedFloor(fx); 1463 int top = SkFixedFloor(fy); 1464 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0); 1465 SkASSERT(NULL == state.fBounder); 1466 SkASSERT((NULL == state.fClip && state.fAAClip) || 1467 (state.fClip && NULL == state.fAAClip && state.fClip->isRect())); 1468 1469 left += glyph.fLeft; 1470 top += glyph.fTop; 1471 1472 int right = left + glyph.fWidth; 1473 int bottom = top + glyph.fHeight; 1474 1475 SkMask mask; 1476 SkIRect storage; 1477 SkIRect* bounds = &mask.fBounds; 1478 1479 mask.fBounds.set(left, top, right, bottom); 1480 1481 // this extra test is worth it, assuming that most of the time it succeeds 1482 // since we can avoid writing to storage 1483 if (!state.fClipBounds.containsNoEmptyCheck(left, top, right, bottom)) { 1484 if (!storage.intersectNoEmptyCheck(mask.fBounds, state.fClipBounds)) 1485 return; 1486 bounds = &storage; 1487 } 1488 1489 uint8_t* aa = (uint8_t*)glyph.fImage; 1490 if (NULL == aa) { 1491 aa = (uint8_t*)state.fCache->findImage(glyph); 1492 if (NULL == aa) { 1493 return; // can't rasterize glyph 1494 } 1495 } 1496 1497 mask.fRowBytes = glyph.rowBytes(); 1498 mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat); 1499 mask.fImage = aa; 1500 state.fBlitter->blitMask(mask, *bounds); 1501} 1502 1503static void D1G_NoBounder_RgnClip(const SkDraw1Glyph& state, 1504 SkFixed fx, SkFixed fy, 1505 const SkGlyph& glyph) { 1506 int left = SkFixedFloor(fx); 1507 int top = SkFixedFloor(fy); 1508 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0); 1509 SkASSERT(!state.fClip->isRect()); 1510 SkASSERT(NULL == state.fBounder); 1511 1512 SkMask mask; 1513 1514 left += glyph.fLeft; 1515 top += glyph.fTop; 1516 1517 mask.fBounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight); 1518 SkRegion::Cliperator clipper(*state.fClip, mask.fBounds); 1519 1520 if (!clipper.done()) { 1521 const SkIRect& cr = clipper.rect(); 1522 const uint8_t* aa = (const uint8_t*)glyph.fImage; 1523 if (NULL == aa) { 1524 aa = (uint8_t*)state.fCache->findImage(glyph); 1525 if (NULL == aa) { 1526 return; 1527 } 1528 } 1529 1530 mask.fRowBytes = glyph.rowBytes(); 1531 mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat); 1532 mask.fImage = (uint8_t*)aa; 1533 do { 1534 state.fBlitter->blitMask(mask, cr); 1535 clipper.next(); 1536 } while (!clipper.done()); 1537 } 1538} 1539 1540static void D1G_Bounder(const SkDraw1Glyph& state, 1541 SkFixed fx, SkFixed fy, 1542 const SkGlyph& glyph) { 1543 int left = SkFixedFloor(fx); 1544 int top = SkFixedFloor(fy); 1545 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0); 1546 1547 SkMask mask; 1548 1549 left += glyph.fLeft; 1550 top += glyph.fTop; 1551 1552 mask.fBounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight); 1553 SkRegion::Cliperator clipper(*state.fClip, mask.fBounds); 1554 1555 if (!clipper.done()) { 1556 const SkIRect& cr = clipper.rect(); 1557 const uint8_t* aa = (const uint8_t*)glyph.fImage; 1558 if (NULL == aa) { 1559 aa = (uint8_t*)state.fCache->findImage(glyph); 1560 if (NULL == aa) { 1561 return; 1562 } 1563 } 1564 1565 // we need to pass the origin, which we approximate with our 1566 // (unadjusted) left,top coordinates (the caller called fixedfloor) 1567 if (state.fBounder->doIRectGlyph(cr, 1568 left - glyph.fLeft, 1569 top - glyph.fTop, glyph)) { 1570 mask.fRowBytes = glyph.rowBytes(); 1571 mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat); 1572 mask.fImage = (uint8_t*)aa; 1573 do { 1574 state.fBlitter->blitMask(mask, cr); 1575 clipper.next(); 1576 } while (!clipper.done()); 1577 } 1578 } 1579} 1580 1581static void D1G_Bounder_AAClip(const SkDraw1Glyph& state, 1582 SkFixed fx, SkFixed fy, 1583 const SkGlyph& glyph) { 1584 int left = SkFixedFloor(fx); 1585 int top = SkFixedFloor(fy); 1586 SkIRect bounds; 1587 bounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight); 1588 1589 if (state.fBounder->doIRectGlyph(bounds, left, top, glyph)) { 1590 D1G_NoBounder_RectClip(state, fx, fy, glyph); 1591 } 1592} 1593 1594static bool hasCustomD1GProc(const SkDraw& draw) { 1595 return draw.fProcs && draw.fProcs->fD1GProc; 1596} 1597 1598static bool needsRasterTextBlit(const SkDraw& draw) { 1599 return !hasCustomD1GProc(draw); 1600} 1601 1602SkDraw1Glyph::Proc SkDraw1Glyph::init(const SkDraw* draw, SkBlitter* blitter, 1603 SkGlyphCache* cache) { 1604 fDraw = draw; 1605 fBounder = draw->fBounder; 1606 fBlitter = blitter; 1607 fCache = cache; 1608 1609 if (cache->isSubpixel()) { 1610 fHalfSampleX = fHalfSampleY = (SK_FixedHalf >> SkGlyph::kSubBits); 1611 } else { 1612 fHalfSampleX = fHalfSampleY = SK_FixedHalf; 1613 } 1614 1615 if (hasCustomD1GProc(*draw)) { 1616 // todo: fix this assumption about clips w/ custom 1617 fClip = draw->fClip; 1618 fClipBounds = fClip->getBounds(); 1619 return draw->fProcs->fD1GProc; 1620 } 1621 1622 if (draw->fRC->isBW()) { 1623 fAAClip = NULL; 1624 fClip = &draw->fRC->bwRgn(); 1625 fClipBounds = fClip->getBounds(); 1626 if (NULL == fBounder) { 1627 if (fClip->isRect()) { 1628 return D1G_NoBounder_RectClip; 1629 } else { 1630 return D1G_NoBounder_RgnClip; 1631 } 1632 } else { 1633 return D1G_Bounder; 1634 } 1635 } else { // aaclip 1636 fAAClip = &draw->fRC->aaRgn(); 1637 fClip = NULL; 1638 fClipBounds = fAAClip->getBounds(); 1639 if (NULL == fBounder) { 1640 return D1G_NoBounder_RectClip; 1641 } else { 1642 return D1G_Bounder_AAClip; 1643 } 1644 } 1645} 1646 1647/////////////////////////////////////////////////////////////////////////////// 1648 1649void SkDraw::drawText(const char text[], size_t byteLength, 1650 SkScalar x, SkScalar y, const SkPaint& paint) const { 1651 SkASSERT(byteLength == 0 || text != NULL); 1652 1653 SkDEBUGCODE(this->validate();) 1654 1655 // nothing to draw 1656 if (text == NULL || byteLength == 0 || fRC->isEmpty()) { 1657 return; 1658 } 1659 1660 // SkScalarRec doesn't currently have a way of representing hairline stroke and 1661 // will fill if its frame-width is 0. 1662 if (/*paint.isLinearText() ||*/ 1663 (fMatrix->hasPerspective()) || 1664 (0 == paint.getStrokeWidth() && SkPaint::kStroke_Style == paint.getStyle())) { 1665 this->drawText_asPaths(text, byteLength, x, y, paint); 1666 return; 1667 } 1668 1669 SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc(); 1670 1671 SkAutoGlyphCache autoCache(paint, &fDevice->fLeakyProperties, fMatrix); 1672 SkGlyphCache* cache = autoCache.getCache(); 1673 1674 // transform our starting point 1675 { 1676 SkPoint loc; 1677 fMatrix->mapXY(x, y, &loc); 1678 x = loc.fX; 1679 y = loc.fY; 1680 } 1681 1682 // need to measure first 1683 if (paint.getTextAlign() != SkPaint::kLeft_Align) { 1684 SkVector stop; 1685 1686 measure_text(cache, glyphCacheProc, text, byteLength, &stop); 1687 1688 SkScalar stopX = stop.fX; 1689 SkScalar stopY = stop.fY; 1690 1691 if (paint.getTextAlign() == SkPaint::kCenter_Align) { 1692 stopX = SkScalarHalf(stopX); 1693 stopY = SkScalarHalf(stopY); 1694 } 1695 x -= stopX; 1696 y -= stopY; 1697 } 1698 1699 const char* stop = text + byteLength; 1700 1701 SkAAClipBlitter aaBlitter; 1702 SkAutoBlitterChoose blitterChooser; 1703 SkBlitter* blitter = NULL; 1704 if (needsRasterTextBlit(*this)) { 1705 blitterChooser.choose(*fBitmap, *fMatrix, paint); 1706 blitter = blitterChooser.get(); 1707 if (fRC->isAA()) { 1708 aaBlitter.init(blitter, &fRC->aaRgn()); 1709 blitter = &aaBlitter; 1710 } 1711 } 1712 1713 SkAutoKern autokern; 1714 SkDraw1Glyph d1g; 1715 SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache); 1716 1717 SkFixed fxMask = ~0; 1718 SkFixed fyMask = ~0; 1719 if (cache->isSubpixel()) { 1720 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(*fMatrix); 1721 if (kX_SkAxisAlignment == baseline) { 1722 fyMask = 0; 1723 d1g.fHalfSampleY = SK_FixedHalf; 1724 } else if (kY_SkAxisAlignment == baseline) { 1725 fxMask = 0; 1726 d1g.fHalfSampleX = SK_FixedHalf; 1727 } 1728 } 1729 1730 SkFixed fx = SkScalarToFixed(x) + d1g.fHalfSampleX; 1731 SkFixed fy = SkScalarToFixed(y) + d1g.fHalfSampleY; 1732 1733 while (text < stop) { 1734 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask); 1735 1736 fx += autokern.adjust(glyph); 1737 1738 if (glyph.fWidth) { 1739 proc(d1g, fx, fy, glyph); 1740 } 1741 fx += glyph.fAdvanceX; 1742 fy += glyph.fAdvanceY; 1743 } 1744} 1745 1746// last parameter is interpreted as SkFixed [x, y] 1747// return the fixed position, which may be rounded or not by the caller 1748// e.g. subpixel doesn't round 1749typedef void (*AlignProc)(const SkPoint&, const SkGlyph&, SkIPoint*); 1750 1751static void leftAlignProc(const SkPoint& loc, const SkGlyph& glyph, 1752 SkIPoint* dst) { 1753 dst->set(SkScalarToFixed(loc.fX), SkScalarToFixed(loc.fY)); 1754} 1755 1756static void centerAlignProc(const SkPoint& loc, const SkGlyph& glyph, 1757 SkIPoint* dst) { 1758 dst->set(SkScalarToFixed(loc.fX) - (glyph.fAdvanceX >> 1), 1759 SkScalarToFixed(loc.fY) - (glyph.fAdvanceY >> 1)); 1760} 1761 1762static void rightAlignProc(const SkPoint& loc, const SkGlyph& glyph, 1763 SkIPoint* dst) { 1764 dst->set(SkScalarToFixed(loc.fX) - glyph.fAdvanceX, 1765 SkScalarToFixed(loc.fY) - glyph.fAdvanceY); 1766} 1767 1768static AlignProc pick_align_proc(SkPaint::Align align) { 1769 static const AlignProc gProcs[] = { 1770 leftAlignProc, centerAlignProc, rightAlignProc 1771 }; 1772 1773 SkASSERT((unsigned)align < SK_ARRAY_COUNT(gProcs)); 1774 1775 return gProcs[align]; 1776} 1777 1778class TextMapState { 1779public: 1780 mutable SkPoint fLoc; 1781 1782 TextMapState(const SkMatrix& matrix, SkScalar y) 1783 : fMatrix(matrix), fProc(matrix.getMapXYProc()), fY(y) {} 1784 1785 typedef void (*Proc)(const TextMapState&, const SkScalar pos[]); 1786 1787 Proc pickProc(int scalarsPerPosition); 1788 1789private: 1790 const SkMatrix& fMatrix; 1791 SkMatrix::MapXYProc fProc; 1792 SkScalar fY; // ignored by MapXYProc 1793 // these are only used by Only... procs 1794 SkScalar fScaleX, fTransX, fTransformedY; 1795 1796 static void MapXProc(const TextMapState& state, const SkScalar pos[]) { 1797 state.fProc(state.fMatrix, *pos, state.fY, &state.fLoc); 1798 } 1799 1800 static void MapXYProc(const TextMapState& state, const SkScalar pos[]) { 1801 state.fProc(state.fMatrix, pos[0], pos[1], &state.fLoc); 1802 } 1803 1804 static void MapOnlyScaleXProc(const TextMapState& state, 1805 const SkScalar pos[]) { 1806 state.fLoc.set(SkScalarMul(state.fScaleX, *pos) + state.fTransX, 1807 state.fTransformedY); 1808 } 1809 1810 static void MapOnlyTransXProc(const TextMapState& state, 1811 const SkScalar pos[]) { 1812 state.fLoc.set(*pos + state.fTransX, state.fTransformedY); 1813 } 1814}; 1815 1816TextMapState::Proc TextMapState::pickProc(int scalarsPerPosition) { 1817 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); 1818 1819 if (1 == scalarsPerPosition) { 1820 unsigned mtype = fMatrix.getType(); 1821 if (mtype & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)) { 1822 return MapXProc; 1823 } else { 1824 fScaleX = fMatrix.getScaleX(); 1825 fTransX = fMatrix.getTranslateX(); 1826 fTransformedY = SkScalarMul(fY, fMatrix.getScaleY()) + 1827 fMatrix.getTranslateY(); 1828 return (mtype & SkMatrix::kScale_Mask) ? 1829 MapOnlyScaleXProc : MapOnlyTransXProc; 1830 } 1831 } else { 1832 return MapXYProc; 1833 } 1834} 1835 1836////////////////////////////////////////////////////////////////////////////// 1837 1838void SkDraw::drawPosText(const char text[], size_t byteLength, 1839 const SkScalar pos[], SkScalar constY, 1840 int scalarsPerPosition, const SkPaint& paint) const { 1841 SkASSERT(byteLength == 0 || text != NULL); 1842 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); 1843 1844 SkDEBUGCODE(this->validate();) 1845 1846 // nothing to draw 1847 if (text == NULL || byteLength == 0 || fRC->isEmpty()) { 1848 return; 1849 } 1850 1851 if (/*paint.isLinearText() ||*/ 1852 (fMatrix->hasPerspective())) { 1853 // TODO !!!! 1854// this->drawText_asPaths(text, byteLength, x, y, paint); 1855 return; 1856 } 1857 1858 SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc(); 1859 SkAutoGlyphCache autoCache(paint, &fDevice->fLeakyProperties, fMatrix); 1860 SkGlyphCache* cache = autoCache.getCache(); 1861 1862 SkAAClipBlitterWrapper wrapper; 1863 SkAutoBlitterChoose blitterChooser; 1864 SkBlitter* blitter = NULL; 1865 if (needsRasterTextBlit(*this)) { 1866 blitterChooser.choose(*fBitmap, *fMatrix, paint); 1867 blitter = blitterChooser.get(); 1868 if (fRC->isAA()) { 1869 wrapper.init(*fRC, blitter); 1870 blitter = wrapper.getBlitter(); 1871 } 1872 } 1873 1874 const char* stop = text + byteLength; 1875 AlignProc alignProc = pick_align_proc(paint.getTextAlign()); 1876 SkDraw1Glyph d1g; 1877 SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache); 1878 TextMapState tms(*fMatrix, constY); 1879 TextMapState::Proc tmsProc = tms.pickProc(scalarsPerPosition); 1880 1881 if (cache->isSubpixel()) { 1882 // maybe we should skip the rounding if linearText is set 1883 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(*fMatrix); 1884 1885 SkFixed fxMask = ~0; 1886 SkFixed fyMask = ~0; 1887 if (kX_SkAxisAlignment == baseline) { 1888 fyMask = 0; 1889#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX 1890 d1g.fHalfSampleY = SK_FixedHalf; 1891#endif 1892 } else if (kY_SkAxisAlignment == baseline) { 1893 fxMask = 0; 1894#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX 1895 d1g.fHalfSampleX = SK_FixedHalf; 1896#endif 1897 } 1898 1899 if (SkPaint::kLeft_Align == paint.getTextAlign()) { 1900 while (text < stop) { 1901 tmsProc(tms, pos); 1902 1903 SkFixed fx = SkScalarToFixed(tms.fLoc.fX) + d1g.fHalfSampleX; 1904 SkFixed fy = SkScalarToFixed(tms.fLoc.fY) + d1g.fHalfSampleY; 1905 1906 const SkGlyph& glyph = glyphCacheProc(cache, &text, 1907 fx & fxMask, fy & fyMask); 1908 1909 if (glyph.fWidth) { 1910 proc(d1g, fx, fy, glyph); 1911 } 1912 pos += scalarsPerPosition; 1913 } 1914 } else { 1915 while (text < stop) { 1916 const char* currentText = text; 1917 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0); 1918 1919 if (metricGlyph.fWidth) { 1920 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;) 1921 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;) 1922 1923 tmsProc(tms, pos); 1924 SkIPoint fixedLoc; 1925 alignProc(tms.fLoc, metricGlyph, &fixedLoc); 1926 1927 SkFixed fx = fixedLoc.fX + d1g.fHalfSampleX; 1928 SkFixed fy = fixedLoc.fY + d1g.fHalfSampleY; 1929 1930 // have to call again, now that we've been "aligned" 1931 const SkGlyph& glyph = glyphCacheProc(cache, ¤tText, 1932 fx & fxMask, fy & fyMask); 1933 // the assumption is that the metrics haven't changed 1934 SkASSERT(prevAdvX == glyph.fAdvanceX); 1935 SkASSERT(prevAdvY == glyph.fAdvanceY); 1936 SkASSERT(glyph.fWidth); 1937 1938 proc(d1g, fx, fy, glyph); 1939 } 1940 pos += scalarsPerPosition; 1941 } 1942 } 1943 } else { // not subpixel 1944 if (SkPaint::kLeft_Align == paint.getTextAlign()) { 1945 while (text < stop) { 1946 // the last 2 parameters are ignored 1947 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); 1948 1949 if (glyph.fWidth) { 1950 tmsProc(tms, pos); 1951 1952 proc(d1g, 1953 SkScalarToFixed(tms.fLoc.fX) + SK_FixedHalf, //d1g.fHalfSampleX, 1954 SkScalarToFixed(tms.fLoc.fY) + SK_FixedHalf, //d1g.fHalfSampleY, 1955 glyph); 1956 } 1957 pos += scalarsPerPosition; 1958 } 1959 } else { 1960 while (text < stop) { 1961 // the last 2 parameters are ignored 1962 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); 1963 1964 if (glyph.fWidth) { 1965 tmsProc(tms, pos); 1966 1967 SkIPoint fixedLoc; 1968 alignProc(tms.fLoc, glyph, &fixedLoc); 1969 1970 proc(d1g, 1971 fixedLoc.fX + SK_FixedHalf, //d1g.fHalfSampleX, 1972 fixedLoc.fY + SK_FixedHalf, //d1g.fHalfSampleY, 1973 glyph); 1974 } 1975 pos += scalarsPerPosition; 1976 } 1977 } 1978 } 1979} 1980 1981#if defined _WIN32 && _MSC_VER >= 1300 1982#pragma warning ( pop ) 1983#endif 1984 1985/////////////////////////////////////////////////////////////////////////////// 1986 1987#include "SkPathMeasure.h" 1988 1989static void morphpoints(SkPoint dst[], const SkPoint src[], int count, 1990 SkPathMeasure& meas, const SkMatrix& matrix) { 1991 SkMatrix::MapXYProc proc = matrix.getMapXYProc(); 1992 1993 for (int i = 0; i < count; i++) { 1994 SkPoint pos; 1995 SkVector tangent; 1996 1997 proc(matrix, src[i].fX, src[i].fY, &pos); 1998 SkScalar sx = pos.fX; 1999 SkScalar sy = pos.fY; 2000 2001 if (!meas.getPosTan(sx, &pos, &tangent)) { 2002 // set to 0 if the measure failed, so that we just set dst == pos 2003 tangent.set(0, 0); 2004 } 2005 2006 /* This is the old way (that explains our approach but is way too slow 2007 SkMatrix matrix; 2008 SkPoint pt; 2009 2010 pt.set(sx, sy); 2011 matrix.setSinCos(tangent.fY, tangent.fX); 2012 matrix.preTranslate(-sx, 0); 2013 matrix.postTranslate(pos.fX, pos.fY); 2014 matrix.mapPoints(&dst[i], &pt, 1); 2015 */ 2016 dst[i].set(pos.fX - SkScalarMul(tangent.fY, sy), 2017 pos.fY + SkScalarMul(tangent.fX, sy)); 2018 } 2019} 2020 2021/* TODO 2022 2023 Need differentially more subdivisions when the follow-path is curvy. Not sure how to 2024 determine that, but we need it. I guess a cheap answer is let the caller tell us, 2025 but that seems like a cop-out. Another answer is to get Rob Johnson to figure it out. 2026*/ 2027static void morphpath(SkPath* dst, const SkPath& src, SkPathMeasure& meas, 2028 const SkMatrix& matrix) { 2029 SkPath::Iter iter(src, false); 2030 SkPoint srcP[4], dstP[3]; 2031 SkPath::Verb verb; 2032 2033 while ((verb = iter.next(srcP)) != SkPath::kDone_Verb) { 2034 switch (verb) { 2035 case SkPath::kMove_Verb: 2036 morphpoints(dstP, srcP, 1, meas, matrix); 2037 dst->moveTo(dstP[0]); 2038 break; 2039 case SkPath::kLine_Verb: 2040 // turn lines into quads to look bendy 2041 srcP[0].fX = SkScalarAve(srcP[0].fX, srcP[1].fX); 2042 srcP[0].fY = SkScalarAve(srcP[0].fY, srcP[1].fY); 2043 morphpoints(dstP, srcP, 2, meas, matrix); 2044 dst->quadTo(dstP[0], dstP[1]); 2045 break; 2046 case SkPath::kQuad_Verb: 2047 morphpoints(dstP, &srcP[1], 2, meas, matrix); 2048 dst->quadTo(dstP[0], dstP[1]); 2049 break; 2050 case SkPath::kCubic_Verb: 2051 morphpoints(dstP, &srcP[1], 3, meas, matrix); 2052 dst->cubicTo(dstP[0], dstP[1], dstP[2]); 2053 break; 2054 case SkPath::kClose_Verb: 2055 dst->close(); 2056 break; 2057 default: 2058 SkDEBUGFAIL("unknown verb"); 2059 break; 2060 } 2061 } 2062} 2063 2064void SkDraw::drawTextOnPath(const char text[], size_t byteLength, 2065 const SkPath& follow, const SkMatrix* matrix, 2066 const SkPaint& paint) const { 2067 SkASSERT(byteLength == 0 || text != NULL); 2068 2069 // nothing to draw 2070 if (text == NULL || byteLength == 0 || fRC->isEmpty()) { 2071 return; 2072 } 2073 2074 SkTextToPathIter iter(text, byteLength, paint, true); 2075 SkPathMeasure meas(follow, false); 2076 SkScalar hOffset = 0; 2077 2078 // need to measure first 2079 if (paint.getTextAlign() != SkPaint::kLeft_Align) { 2080 SkScalar pathLen = meas.getLength(); 2081 if (paint.getTextAlign() == SkPaint::kCenter_Align) { 2082 pathLen = SkScalarHalf(pathLen); 2083 } 2084 hOffset += pathLen; 2085 } 2086 2087 const SkPath* iterPath; 2088 SkScalar xpos; 2089 SkMatrix scaledMatrix; 2090 SkScalar scale = iter.getPathScale(); 2091 2092 scaledMatrix.setScale(scale, scale); 2093 2094 while (iter.next(&iterPath, &xpos)) { 2095 if (iterPath) { 2096 SkPath tmp; 2097 SkMatrix m(scaledMatrix); 2098 2099 m.postTranslate(xpos + hOffset, 0); 2100 if (matrix) { 2101 m.postConcat(*matrix); 2102 } 2103 morphpath(&tmp, *iterPath, meas, m); 2104 if (fDevice) { 2105 fDevice->drawPath(*this, tmp, iter.getPaint(), NULL, true); 2106 } else { 2107 this->drawPath(tmp, iter.getPaint(), NULL, true); 2108 } 2109 } 2110 } 2111} 2112 2113#ifdef SK_BUILD_FOR_ANDROID 2114void SkDraw::drawPosTextOnPath(const char text[], size_t byteLength, 2115 const SkPoint pos[], const SkPaint& paint, 2116 const SkPath& path, const SkMatrix* matrix) const { 2117 // nothing to draw 2118 if (text == NULL || byteLength == 0 || fRC->isEmpty()) { 2119 return; 2120 } 2121 2122 SkMatrix scaledMatrix; 2123 SkPathMeasure meas(path, false); 2124 2125 SkMeasureCacheProc glyphCacheProc = paint.getMeasureCacheProc( 2126 SkPaint::kForward_TextBufferDirection, true); 2127 2128 // Copied (modified) from SkTextToPathIter constructor to setup paint 2129 SkPaint tempPaint(paint); 2130 2131 tempPaint.setLinearText(true); 2132 tempPaint.setMaskFilter(NULL); // don't want this affecting our path-cache lookup 2133 2134 if (tempPaint.getPathEffect() == NULL && !(tempPaint.getStrokeWidth() > 0 2135 && tempPaint.getStyle() != SkPaint::kFill_Style)) { 2136 tempPaint.setStyle(SkPaint::kFill_Style); 2137 tempPaint.setPathEffect(NULL); 2138 } 2139 // End copied from SkTextToPathIter constructor 2140 2141 // detach cache 2142 SkGlyphCache* cache = tempPaint.detachCache(NULL, NULL); 2143 2144 // Must set scale, even if 1 2145 SkScalar scale = SK_Scalar1; 2146 scaledMatrix.setScale(scale, scale); 2147 2148 // Loop over all glyph ids 2149 for (const char* stop = text + byteLength; text < stop; pos++) { 2150 2151 const SkGlyph& glyph = glyphCacheProc(cache, &text); 2152 SkPath tmp; 2153 2154 const SkPath* glyphPath = cache->findPath(glyph); 2155 if (glyphPath == NULL) { 2156 continue; 2157 } 2158 2159 SkMatrix m(scaledMatrix); 2160 m.postTranslate(pos->fX, 0); 2161 2162 if (matrix) { 2163 m.postConcat(*matrix); 2164 } 2165 2166 morphpath(&tmp, *glyphPath, meas, m); 2167 this->drawPath(tmp, tempPaint); 2168 2169 } 2170 2171 // re-attach cache 2172 SkGlyphCache::AttachCache(cache); 2173} 2174#endif 2175 2176/////////////////////////////////////////////////////////////////////////////// 2177 2178struct VertState { 2179 int f0, f1, f2; 2180 2181 VertState(int vCount, const uint16_t indices[], int indexCount) 2182 : fIndices(indices) { 2183 fCurrIndex = 0; 2184 if (indices) { 2185 fCount = indexCount; 2186 } else { 2187 fCount = vCount; 2188 } 2189 } 2190 2191 typedef bool (*Proc)(VertState*); 2192 Proc chooseProc(SkCanvas::VertexMode mode); 2193 2194private: 2195 int fCount; 2196 int fCurrIndex; 2197 const uint16_t* fIndices; 2198 2199 static bool Triangles(VertState*); 2200 static bool TrianglesX(VertState*); 2201 static bool TriangleStrip(VertState*); 2202 static bool TriangleStripX(VertState*); 2203 static bool TriangleFan(VertState*); 2204 static bool TriangleFanX(VertState*); 2205}; 2206 2207bool VertState::Triangles(VertState* state) { 2208 int index = state->fCurrIndex; 2209 if (index + 3 > state->fCount) { 2210 return false; 2211 } 2212 state->f0 = index + 0; 2213 state->f1 = index + 1; 2214 state->f2 = index + 2; 2215 state->fCurrIndex = index + 3; 2216 return true; 2217} 2218 2219bool VertState::TrianglesX(VertState* state) { 2220 const uint16_t* indices = state->fIndices; 2221 int index = state->fCurrIndex; 2222 if (index + 3 > state->fCount) { 2223 return false; 2224 } 2225 state->f0 = indices[index + 0]; 2226 state->f1 = indices[index + 1]; 2227 state->f2 = indices[index + 2]; 2228 state->fCurrIndex = index + 3; 2229 return true; 2230} 2231 2232bool VertState::TriangleStrip(VertState* state) { 2233 int index = state->fCurrIndex; 2234 if (index + 3 > state->fCount) { 2235 return false; 2236 } 2237 state->f2 = index + 2; 2238 if (index & 1) { 2239 state->f0 = index + 1; 2240 state->f1 = index + 0; 2241 } else { 2242 state->f0 = index + 0; 2243 state->f1 = index + 1; 2244 } 2245 state->fCurrIndex = index + 1; 2246 return true; 2247} 2248 2249bool VertState::TriangleStripX(VertState* state) { 2250 const uint16_t* indices = state->fIndices; 2251 int index = state->fCurrIndex; 2252 if (index + 3 > state->fCount) { 2253 return false; 2254 } 2255 state->f2 = indices[index + 2]; 2256 if (index & 1) { 2257 state->f0 = indices[index + 1]; 2258 state->f1 = indices[index + 0]; 2259 } else { 2260 state->f0 = indices[index + 0]; 2261 state->f1 = indices[index + 1]; 2262 } 2263 state->fCurrIndex = index + 1; 2264 return true; 2265} 2266 2267bool VertState::TriangleFan(VertState* state) { 2268 int index = state->fCurrIndex; 2269 if (index + 3 > state->fCount) { 2270 return false; 2271 } 2272 state->f0 = 0; 2273 state->f1 = index + 1; 2274 state->f2 = index + 2; 2275 state->fCurrIndex = index + 1; 2276 return true; 2277} 2278 2279bool VertState::TriangleFanX(VertState* state) { 2280 const uint16_t* indices = state->fIndices; 2281 int index = state->fCurrIndex; 2282 if (index + 3 > state->fCount) { 2283 return false; 2284 } 2285 state->f0 = indices[0]; 2286 state->f1 = indices[index + 1]; 2287 state->f2 = indices[index + 2]; 2288 state->fCurrIndex = index + 1; 2289 return true; 2290} 2291 2292VertState::Proc VertState::chooseProc(SkCanvas::VertexMode mode) { 2293 switch (mode) { 2294 case SkCanvas::kTriangles_VertexMode: 2295 return fIndices ? TrianglesX : Triangles; 2296 case SkCanvas::kTriangleStrip_VertexMode: 2297 return fIndices ? TriangleStripX : TriangleStrip; 2298 case SkCanvas::kTriangleFan_VertexMode: 2299 return fIndices ? TriangleFanX : TriangleFan; 2300 default: 2301 return NULL; 2302 } 2303} 2304 2305typedef void (*HairProc)(const SkPoint&, const SkPoint&, const SkRasterClip&, 2306 SkBlitter*); 2307 2308static HairProc ChooseHairProc(bool doAntiAlias) { 2309 return doAntiAlias ? SkScan::AntiHairLine : SkScan::HairLine; 2310} 2311 2312static bool texture_to_matrix(const VertState& state, const SkPoint verts[], 2313 const SkPoint texs[], SkMatrix* matrix) { 2314 SkPoint src[3], dst[3]; 2315 2316 src[0] = texs[state.f0]; 2317 src[1] = texs[state.f1]; 2318 src[2] = texs[state.f2]; 2319 dst[0] = verts[state.f0]; 2320 dst[1] = verts[state.f1]; 2321 dst[2] = verts[state.f2]; 2322 return matrix->setPolyToPoly(src, dst, 3); 2323} 2324 2325class SkTriColorShader : public SkShader { 2326public: 2327 SkTriColorShader() {} 2328 2329 bool setup(const SkPoint pts[], const SkColor colors[], int, int, int); 2330 2331 virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE; 2332 2333 SK_DEVELOPER_TO_STRING() 2334 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTriColorShader) 2335 2336protected: 2337 SkTriColorShader(SkFlattenableReadBuffer& buffer) : SkShader(buffer) {} 2338 2339private: 2340 SkMatrix fDstToUnit; 2341 SkPMColor fColors[3]; 2342 2343 typedef SkShader INHERITED; 2344}; 2345 2346bool SkTriColorShader::setup(const SkPoint pts[], const SkColor colors[], 2347 int index0, int index1, int index2) { 2348 2349 fColors[0] = SkPreMultiplyColor(colors[index0]); 2350 fColors[1] = SkPreMultiplyColor(colors[index1]); 2351 fColors[2] = SkPreMultiplyColor(colors[index2]); 2352 2353 SkMatrix m, im; 2354 m.reset(); 2355 m.set(0, pts[index1].fX - pts[index0].fX); 2356 m.set(1, pts[index2].fX - pts[index0].fX); 2357 m.set(2, pts[index0].fX); 2358 m.set(3, pts[index1].fY - pts[index0].fY); 2359 m.set(4, pts[index2].fY - pts[index0].fY); 2360 m.set(5, pts[index0].fY); 2361 if (!m.invert(&im)) { 2362 return false; 2363 } 2364 return fDstToUnit.setConcat(im, this->getTotalInverse()); 2365} 2366 2367#include "SkColorPriv.h" 2368#include "SkComposeShader.h" 2369 2370static int ScalarTo256(SkScalar v) { 2371 int scale = SkScalarToFixed(v) >> 8; 2372 if (scale < 0) { 2373 scale = 0; 2374 } 2375 if (scale > 255) { 2376 scale = 255; 2377 } 2378 return SkAlpha255To256(scale); 2379} 2380 2381void SkTriColorShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) { 2382 SkPoint src; 2383 2384 for (int i = 0; i < count; i++) { 2385 fDstToUnit.mapXY(SkIntToScalar(x), SkIntToScalar(y), &src); 2386 x += 1; 2387 2388 int scale1 = ScalarTo256(src.fX); 2389 int scale2 = ScalarTo256(src.fY); 2390 int scale0 = 256 - scale1 - scale2; 2391 if (scale0 < 0) { 2392 if (scale1 > scale2) { 2393 scale2 = 256 - scale1; 2394 } else { 2395 scale1 = 256 - scale2; 2396 } 2397 scale0 = 0; 2398 } 2399 2400 dstC[i] = SkAlphaMulQ(fColors[0], scale0) + 2401 SkAlphaMulQ(fColors[1], scale1) + 2402 SkAlphaMulQ(fColors[2], scale2); 2403 } 2404} 2405 2406#ifdef SK_DEVELOPER 2407void SkTriColorShader::toString(SkString* str) const { 2408 str->append("SkTriColorShader: ("); 2409 2410 this->INHERITED::toString(str); 2411 2412 str->append(")"); 2413} 2414#endif 2415 2416void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count, 2417 const SkPoint vertices[], const SkPoint textures[], 2418 const SkColor colors[], SkXfermode* xmode, 2419 const uint16_t indices[], int indexCount, 2420 const SkPaint& paint) const { 2421 SkASSERT(0 == count || NULL != vertices); 2422 2423 // abort early if there is nothing to draw 2424 if (count < 3 || (indices && indexCount < 3) || fRC->isEmpty()) { 2425 return; 2426 } 2427 2428 // transform out vertices into device coordinates 2429 SkAutoSTMalloc<16, SkPoint> storage(count); 2430 SkPoint* devVerts = storage.get(); 2431 fMatrix->mapPoints(devVerts, vertices, count); 2432 2433 if (fBounder) { 2434 SkRect bounds; 2435 bounds.set(devVerts, count); 2436 if (!fBounder->doRect(bounds, paint)) { 2437 return; 2438 } 2439 } 2440 2441 /* 2442 We can draw the vertices in 1 of 4 ways: 2443 2444 - solid color (no shader/texture[], no colors[]) 2445 - just colors (no shader/texture[], has colors[]) 2446 - just texture (has shader/texture[], no colors[]) 2447 - colors * texture (has shader/texture[], has colors[]) 2448 2449 Thus for texture drawing, we need both texture[] and a shader. 2450 */ 2451 2452 SkTriColorShader triShader; // must be above declaration of p 2453 SkPaint p(paint); 2454 2455 SkShader* shader = p.getShader(); 2456 if (NULL == shader) { 2457 // if we have no shader, we ignore the texture coordinates 2458 textures = NULL; 2459 } else if (NULL == textures) { 2460 // if we don't have texture coordinates, ignore the shader 2461 p.setShader(NULL); 2462 shader = NULL; 2463 } 2464 2465 // setup the custom shader (if needed) 2466 if (NULL != colors) { 2467 if (NULL == textures) { 2468 // just colors (no texture) 2469 shader = p.setShader(&triShader); 2470 } else { 2471 // colors * texture 2472 SkASSERT(shader); 2473 bool releaseMode = false; 2474 if (NULL == xmode) { 2475 xmode = SkXfermode::Create(SkXfermode::kModulate_Mode); 2476 releaseMode = true; 2477 } 2478 SkShader* compose = SkNEW_ARGS(SkComposeShader, 2479 (&triShader, shader, xmode)); 2480 p.setShader(compose)->unref(); 2481 if (releaseMode) { 2482 xmode->unref(); 2483 } 2484 shader = compose; 2485 } 2486 } 2487 2488 SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, p); 2489 // important that we abort early, as below we may manipulate the shader 2490 // and that is only valid if the shader returned true from setContext. 2491 // If it returned false, then our blitter will be the NullBlitter. 2492 if (blitter->isNullBlitter()) { 2493 return; 2494 } 2495 2496 // setup our state and function pointer for iterating triangles 2497 VertState state(count, indices, indexCount); 2498 VertState::Proc vertProc = state.chooseProc(vmode); 2499 2500 if (NULL != textures || NULL != colors) { 2501 SkMatrix tempM; 2502 SkMatrix savedLocalM; 2503 if (shader) { 2504 savedLocalM = shader->getLocalMatrix(); 2505 } 2506 2507 // setContext has already been called and verified to return true 2508 // by the constructor of SkAutoBlitterChoose 2509 bool prevContextSuccess = true; 2510 while (vertProc(&state)) { 2511 if (NULL != textures) { 2512 if (texture_to_matrix(state, vertices, textures, &tempM)) { 2513 tempM.postConcat(savedLocalM); 2514 shader->setLocalMatrix(tempM); 2515 // Need to recall setContext since we changed the local matrix. 2516 // However, we also need to balance the calls this with a 2517 // call to endContext which requires tracking the result of 2518 // the previous call to setContext. 2519 if (prevContextSuccess) { 2520 shader->endContext(); 2521 } 2522 prevContextSuccess = shader->setContext(*fBitmap, p, *fMatrix); 2523 if (!prevContextSuccess) { 2524 continue; 2525 } 2526 } 2527 } 2528 if (NULL != colors) { 2529 if (!triShader.setup(vertices, colors, 2530 state.f0, state.f1, state.f2)) { 2531 continue; 2532 } 2533 } 2534 2535 SkPoint tmp[] = { 2536 devVerts[state.f0], devVerts[state.f1], devVerts[state.f2] 2537 }; 2538 SkScan::FillTriangle(tmp, *fRC, blitter.get()); 2539 } 2540 2541 // now restore the shader's original local matrix 2542 if (NULL != shader) { 2543 shader->setLocalMatrix(savedLocalM); 2544 } 2545 2546 // If the final call to setContext fails we must make it suceed so that the 2547 // call to endContext in the destructor for SkAutoBlitterChoose is balanced. 2548 if (!prevContextSuccess) { 2549 prevContextSuccess = shader->setContext(*fBitmap, paint, SkMatrix::I()); 2550 SkASSERT(prevContextSuccess); 2551 } 2552 } else { 2553 // no colors[] and no texture 2554 HairProc hairProc = ChooseHairProc(paint.isAntiAlias()); 2555 const SkRasterClip& clip = *fRC; 2556 while (vertProc(&state)) { 2557 hairProc(devVerts[state.f0], devVerts[state.f1], clip, blitter.get()); 2558 hairProc(devVerts[state.f1], devVerts[state.f2], clip, blitter.get()); 2559 hairProc(devVerts[state.f2], devVerts[state.f0], clip, blitter.get()); 2560 } 2561 } 2562} 2563 2564/////////////////////////////////////////////////////////////////////////////// 2565/////////////////////////////////////////////////////////////////////////////// 2566 2567#ifdef SK_DEBUG 2568 2569void SkDraw::validate() const { 2570 SkASSERT(fBitmap != NULL); 2571 SkASSERT(fMatrix != NULL); 2572 SkASSERT(fClip != NULL); 2573 SkASSERT(fRC != NULL); 2574 2575 const SkIRect& cr = fRC->getBounds(); 2576 SkIRect br; 2577 2578 br.set(0, 0, fBitmap->width(), fBitmap->height()); 2579 SkASSERT(cr.isEmpty() || br.contains(cr)); 2580} 2581 2582#endif 2583 2584/////////////////////////////////////////////////////////////////////////////// 2585 2586SkBounder::SkBounder() { 2587 // initialize up front. This gets reset by SkCanvas before each draw call. 2588 fClip = &SkRegion::GetEmptyRegion(); 2589} 2590 2591bool SkBounder::doIRect(const SkIRect& r) { 2592 SkIRect rr; 2593 return rr.intersect(fClip->getBounds(), r) && this->onIRect(rr); 2594} 2595 2596// TODO: change the prototype to take fixed, and update the callers 2597bool SkBounder::doIRectGlyph(const SkIRect& r, int x, int y, 2598 const SkGlyph& glyph) { 2599 SkIRect rr; 2600 if (!rr.intersect(fClip->getBounds(), r)) { 2601 return false; 2602 } 2603 GlyphRec rec; 2604 rec.fLSB.set(SkIntToFixed(x), SkIntToFixed(y)); 2605 rec.fRSB.set(rec.fLSB.fX + glyph.fAdvanceX, 2606 rec.fLSB.fY + glyph.fAdvanceY); 2607 rec.fGlyphID = glyph.getGlyphID(); 2608 rec.fFlags = 0; 2609 return this->onIRectGlyph(rr, rec); 2610} 2611 2612bool SkBounder::doHairline(const SkPoint& pt0, const SkPoint& pt1, 2613 const SkPaint& paint) { 2614 SkIRect r; 2615 SkScalar v0, v1; 2616 2617 v0 = pt0.fX; 2618 v1 = pt1.fX; 2619 if (v0 > v1) { 2620 SkTSwap<SkScalar>(v0, v1); 2621 } 2622 r.fLeft = SkScalarFloor(v0); 2623 r.fRight = SkScalarCeil(v1); 2624 2625 v0 = pt0.fY; 2626 v1 = pt1.fY; 2627 if (v0 > v1) { 2628 SkTSwap<SkScalar>(v0, v1); 2629 } 2630 r.fTop = SkScalarFloor(v0); 2631 r.fBottom = SkScalarCeil(v1); 2632 2633 if (paint.isAntiAlias()) { 2634 r.inset(-1, -1); 2635 } 2636 return this->doIRect(r); 2637} 2638 2639bool SkBounder::doRect(const SkRect& rect, const SkPaint& paint) { 2640 SkIRect r; 2641 2642 if (paint.getStyle() == SkPaint::kFill_Style) { 2643 rect.round(&r); 2644 } else { 2645 int rad = -1; 2646 rect.roundOut(&r); 2647 if (paint.isAntiAlias()) { 2648 rad = -2; 2649 } 2650 r.inset(rad, rad); 2651 } 2652 return this->doIRect(r); 2653} 2654 2655bool SkBounder::doPath(const SkPath& path, const SkPaint& paint, bool doFill) { 2656 SkIRect r; 2657 const SkRect& bounds = path.getBounds(); 2658 2659 if (doFill) { 2660 bounds.round(&r); 2661 } else { // hairline 2662 bounds.roundOut(&r); 2663 } 2664 2665 if (paint.isAntiAlias()) { 2666 r.inset(-1, -1); 2667 } 2668 return this->doIRect(r); 2669} 2670 2671void SkBounder::commit() { 2672 // override in subclass 2673} 2674 2675//////////////////////////////////////////////////////////////////////////////////////////////// 2676 2677#include "SkPath.h" 2678#include "SkDraw.h" 2679#include "SkRegion.h" 2680#include "SkBlitter.h" 2681 2682static bool compute_bounds(const SkPath& devPath, const SkIRect* clipBounds, 2683 const SkMaskFilter* filter, const SkMatrix* filterMatrix, 2684 SkIRect* bounds) { 2685 if (devPath.isEmpty()) { 2686 return false; 2687 } 2688 2689 // init our bounds from the path 2690 { 2691 SkRect pathBounds = devPath.getBounds(); 2692 pathBounds.inset(-SK_ScalarHalf, -SK_ScalarHalf); 2693 pathBounds.roundOut(bounds); 2694 } 2695 2696 SkIPoint margin = SkIPoint::Make(0, 0); 2697 if (filter) { 2698 SkASSERT(filterMatrix); 2699 2700 SkMask srcM, dstM; 2701 2702 srcM.fBounds = *bounds; 2703 srcM.fFormat = SkMask::kA8_Format; 2704 srcM.fImage = NULL; 2705 if (!filter->filterMask(&dstM, srcM, *filterMatrix, &margin)) { 2706 return false; 2707 } 2708 } 2709 2710 // (possibly) trim the bounds to reflect the clip 2711 // (plus whatever slop the filter needs) 2712 if (clipBounds) { 2713 SkIRect tmp = *clipBounds; 2714 // Ugh. Guard against gigantic margins from wacky filters. Without this 2715 // check we can request arbitrary amounts of slop beyond our visible 2716 // clip, and bring down the renderer (at least on finite RAM machines 2717 // like handsets, etc.). Need to balance this invented value between 2718 // quality of large filters like blurs, and the corresponding memory 2719 // requests. 2720 static const int MAX_MARGIN = 128; 2721 tmp.inset(-SkMin32(margin.fX, MAX_MARGIN), 2722 -SkMin32(margin.fY, MAX_MARGIN)); 2723 if (!bounds->intersect(tmp)) { 2724 return false; 2725 } 2726 } 2727 2728 return true; 2729} 2730 2731static void draw_into_mask(const SkMask& mask, const SkPath& devPath, 2732 SkPaint::Style style) { 2733 SkBitmap bm; 2734 SkDraw draw; 2735 SkRasterClip clip; 2736 SkMatrix matrix; 2737 SkPaint paint; 2738 2739 bm.setConfig(SkBitmap::kA8_Config, mask.fBounds.width(), mask.fBounds.height(), mask.fRowBytes); 2740 bm.setPixels(mask.fImage); 2741 2742 clip.setRect(SkIRect::MakeWH(mask.fBounds.width(), mask.fBounds.height())); 2743 matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft), 2744 -SkIntToScalar(mask.fBounds.fTop)); 2745 2746 draw.fBitmap = &bm; 2747 draw.fRC = &clip; 2748 draw.fClip = &clip.bwRgn(); 2749 draw.fMatrix = &matrix; 2750 draw.fBounder = NULL; 2751 paint.setAntiAlias(true); 2752 paint.setStyle(style); 2753 draw.drawPath(devPath, paint); 2754} 2755 2756bool SkDraw::DrawToMask(const SkPath& devPath, const SkIRect* clipBounds, 2757 const SkMaskFilter* filter, const SkMatrix* filterMatrix, 2758 SkMask* mask, SkMask::CreateMode mode, 2759 SkPaint::Style style) { 2760 if (SkMask::kJustRenderImage_CreateMode != mode) { 2761 if (!compute_bounds(devPath, clipBounds, filter, filterMatrix, &mask->fBounds)) 2762 return false; 2763 } 2764 2765 if (SkMask::kComputeBoundsAndRenderImage_CreateMode == mode) { 2766 mask->fFormat = SkMask::kA8_Format; 2767 mask->fRowBytes = mask->fBounds.width(); 2768 size_t size = mask->computeImageSize(); 2769 if (0 == size) { 2770 // we're too big to allocate the mask, abort 2771 return false; 2772 } 2773 mask->fImage = SkMask::AllocImage(size); 2774 memset(mask->fImage, 0, mask->computeImageSize()); 2775 } 2776 2777 if (SkMask::kJustComputeBounds_CreateMode != mode) { 2778 draw_into_mask(*mask, devPath, style); 2779 } 2780 2781 return true; 2782} 2783