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