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