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