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