SkDraw.cpp revision f85d2a4fa1b71e6ee28518431e2a34df5683bc81
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#define __STDC_LIMIT_MACROS 8 9#include "SkDraw.h" 10#include "SkBlendModePriv.h" 11#include "SkBlitter.h" 12#include "SkCanvas.h" 13#include "SkColorPriv.h" 14#include "SkDevice.h" 15#include "SkDeviceLooper.h" 16#include "SkFindAndPlaceGlyph.h" 17#include "SkFixed.h" 18#include "SkMaskFilter.h" 19#include "SkMatrix.h" 20#include "SkPaint.h" 21#include "SkPathEffect.h" 22#include "SkRasterClip.h" 23#include "SkRasterizer.h" 24#include "SkRRect.h" 25#include "SkScan.h" 26#include "SkShader.h" 27#include "SkSmallAllocator.h" 28#include "SkString.h" 29#include "SkStroke.h" 30#include "SkStrokeRec.h" 31#include "SkTemplates.h" 32#include "SkTextMapStateProc.h" 33#include "SkTLazy.h" 34#include "SkUtils.h" 35#include "SkVertState.h" 36#include "SkXfermode.h" 37 38#include "SkBitmapProcShader.h" 39#include "SkDrawProcs.h" 40#include "SkMatrixUtils.h" 41 42//#define TRACE_BITMAP_DRAWS 43 44// Helper function to fix code gen bug on ARM64. 45// See SkFindAndPlaceGlyph.h for more details. 46void FixGCC49Arm64Bug(int v) { } 47 48/** Helper for allocating small blitters on the stack. 49 */ 50class SkAutoBlitterChoose : SkNoncopyable { 51public: 52 SkAutoBlitterChoose() { 53 fBlitter = nullptr; 54 } 55 SkAutoBlitterChoose(const SkPixmap& dst, const SkMatrix& matrix, 56 const SkPaint& paint, bool drawCoverage = false) { 57 fBlitter = SkBlitter::Choose(dst, matrix, paint, &fAllocator, drawCoverage); 58 } 59 60 SkBlitter* operator->() { return fBlitter; } 61 SkBlitter* get() const { return fBlitter; } 62 63 void choose(const SkPixmap& dst, const SkMatrix& matrix, 64 const SkPaint& paint, bool drawCoverage = false) { 65 SkASSERT(!fBlitter); 66 fBlitter = SkBlitter::Choose(dst, matrix, paint, &fAllocator, drawCoverage); 67 } 68 69private: 70 // Owned by fAllocator, which will handle the delete. 71 SkBlitter* fBlitter; 72 SkTBlitterAllocator fAllocator; 73}; 74#define SkAutoBlitterChoose(...) SK_REQUIRE_LOCAL_VAR(SkAutoBlitterChoose) 75 76/** 77 * Since we are providing the storage for the shader (to avoid the perf cost 78 * of calling new) we insist that in our destructor we can account for all 79 * owners of the shader. 80 */ 81class SkAutoBitmapShaderInstall : SkNoncopyable { 82public: 83 SkAutoBitmapShaderInstall(const SkBitmap& src, const SkPaint& paint, 84 const SkMatrix* localMatrix = nullptr) 85 : fPaint(paint) /* makes a copy of the paint */ { 86 fPaint.setShader(SkMakeBitmapShader(src, SkShader::kClamp_TileMode, 87 SkShader::kClamp_TileMode, localMatrix, 88 kNever_SkCopyPixelsMode, 89 &fAllocator)); 90 // we deliberately left the shader with an owner-count of 2 91 fPaint.getShader()->ref(); 92 SkASSERT(2 == fPaint.getShader()->getRefCnt()); 93 } 94 95 ~SkAutoBitmapShaderInstall() { 96 // since fAllocator will destroy shader, we insist that owners == 2 97 SkASSERT(2 == fPaint.getShader()->getRefCnt()); 98 99 fPaint.setShader(nullptr); // unref the shader by 1 100 101 } 102 103 // return the new paint that has the shader applied 104 const SkPaint& paintWithShader() const { return fPaint; } 105 106private: 107 // copy of caller's paint (which we then modify) 108 SkPaint fPaint; 109 // Stores the shader. 110 SkTBlitterAllocator fAllocator; 111}; 112#define SkAutoBitmapShaderInstall(...) SK_REQUIRE_LOCAL_VAR(SkAutoBitmapShaderInstall) 113 114/////////////////////////////////////////////////////////////////////////////// 115 116SkDraw::SkDraw() { 117 sk_bzero(this, sizeof(*this)); 118} 119 120bool SkDraw::computeConservativeLocalClipBounds(SkRect* localBounds) const { 121 if (fRC->isEmpty()) { 122 return false; 123 } 124 125 SkMatrix inverse; 126 if (!fMatrix->invert(&inverse)) { 127 return false; 128 } 129 130 SkIRect devBounds = fRC->getBounds(); 131 // outset to have slop for antialasing and hairlines 132 devBounds.outset(1, 1); 133 inverse.mapRect(localBounds, SkRect::Make(devBounds)); 134 return true; 135} 136 137/////////////////////////////////////////////////////////////////////////////// 138 139typedef void (*BitmapXferProc)(void* pixels, size_t bytes, uint32_t data); 140 141static void D_Clear_BitmapXferProc(void* pixels, size_t bytes, uint32_t) { 142 sk_bzero(pixels, bytes); 143} 144 145static void D_Dst_BitmapXferProc(void*, size_t, uint32_t data) {} 146 147static void D32_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) { 148 sk_memset32((uint32_t*)pixels, data, SkToInt(bytes >> 2)); 149} 150 151static void D16_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) { 152 sk_memset16((uint16_t*)pixels, data, SkToInt(bytes >> 1)); 153} 154 155static void DA8_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) { 156 memset(pixels, data, bytes); 157} 158 159static BitmapXferProc ChooseBitmapXferProc(const SkPixmap& dst, const SkPaint& paint, 160 uint32_t* data) { 161 // todo: we can apply colorfilter up front if no shader, so we wouldn't 162 // need to abort this fastpath 163 if (paint.getShader() || paint.getColorFilter()) { 164 return nullptr; 165 } 166 167 SkBlendMode mode = paint.getBlendMode(); 168 SkColor color = paint.getColor(); 169 170 // collaps modes based on color... 171 if (SkBlendMode::kSrcOver == mode) { 172 unsigned alpha = SkColorGetA(color); 173 if (0 == alpha) { 174 mode = SkBlendMode::kDst; 175 } else if (0xFF == alpha) { 176 mode = SkBlendMode::kSrc; 177 } 178 } 179 180 switch (mode) { 181 case SkBlendMode::kClear: 182// SkDebugf("--- D_Clear_BitmapXferProc\n"); 183 return D_Clear_BitmapXferProc; // ignore data 184 case SkBlendMode::kDst: 185// SkDebugf("--- D_Dst_BitmapXferProc\n"); 186 return D_Dst_BitmapXferProc; // ignore data 187 case SkBlendMode::kSrc: { 188 /* 189 should I worry about dithering for the lower depths? 190 */ 191 SkPMColor pmc = SkPreMultiplyColor(color); 192 switch (dst.colorType()) { 193 case kN32_SkColorType: 194 if (data) { 195 *data = pmc; 196 } 197// SkDebugf("--- D32_Src_BitmapXferProc\n"); 198 return D32_Src_BitmapXferProc; 199 case kRGB_565_SkColorType: 200 if (data) { 201 *data = SkPixel32ToPixel16(pmc); 202 } 203// SkDebugf("--- D16_Src_BitmapXferProc\n"); 204 return D16_Src_BitmapXferProc; 205 case kAlpha_8_SkColorType: 206 if (data) { 207 *data = SkGetPackedA32(pmc); 208 } 209// SkDebugf("--- DA8_Src_BitmapXferProc\n"); 210 return DA8_Src_BitmapXferProc; 211 default: 212 break; 213 } 214 break; 215 } 216 default: 217 break; 218 } 219 return nullptr; 220} 221 222static void CallBitmapXferProc(const SkPixmap& dst, const SkIRect& rect, BitmapXferProc proc, 223 uint32_t procData) { 224 int shiftPerPixel; 225 switch (dst.colorType()) { 226 case kN32_SkColorType: 227 shiftPerPixel = 2; 228 break; 229 case kRGB_565_SkColorType: 230 shiftPerPixel = 1; 231 break; 232 case kAlpha_8_SkColorType: 233 shiftPerPixel = 0; 234 break; 235 default: 236 SkDEBUGFAIL("Can't use xferproc on this config"); 237 return; 238 } 239 240 uint8_t* pixels = (uint8_t*)dst.writable_addr(); 241 SkASSERT(pixels); 242 const size_t rowBytes = dst.rowBytes(); 243 const int widthBytes = rect.width() << shiftPerPixel; 244 245 // skip down to the first scanline and X position 246 pixels += rect.fTop * rowBytes + (rect.fLeft << shiftPerPixel); 247 for (int scans = rect.height() - 1; scans >= 0; --scans) { 248 proc(pixels, widthBytes, procData); 249 pixels += rowBytes; 250 } 251} 252 253void SkDraw::drawPaint(const SkPaint& paint) const { 254 SkDEBUGCODE(this->validate();) 255 256 if (fRC->isEmpty()) { 257 return; 258 } 259 260 SkIRect devRect; 261 devRect.set(0, 0, fDst.width(), fDst.height()); 262 263 if (fRC->isBW()) { 264 /* If we don't have a shader (i.e. we're just a solid color) we may 265 be faster to operate directly on the device bitmap, rather than invoking 266 a blitter. Esp. true for xfermodes, which require a colorshader to be 267 present, which is just redundant work. Since we're drawing everywhere 268 in the clip, we don't have to worry about antialiasing. 269 */ 270 uint32_t procData = 0; // to avoid the warning 271 BitmapXferProc proc = ChooseBitmapXferProc(fDst, paint, &procData); 272 if (proc) { 273 if (D_Dst_BitmapXferProc == proc) { // nothing to do 274 return; 275 } 276 277 SkRegion::Iterator iter(fRC->bwRgn()); 278 while (!iter.done()) { 279 CallBitmapXferProc(fDst, iter.rect(), proc, procData); 280 iter.next(); 281 } 282 return; 283 } 284 } 285 286 // normal case: use a blitter 287 SkAutoBlitterChoose blitter(fDst, *fMatrix, paint); 288 SkScan::FillIRect(devRect, *fRC, blitter.get()); 289} 290 291/////////////////////////////////////////////////////////////////////////////// 292 293struct PtProcRec { 294 SkCanvas::PointMode fMode; 295 const SkPaint* fPaint; 296 const SkRegion* fClip; 297 const SkRasterClip* fRC; 298 299 // computed values 300 SkFixed fRadius; 301 302 typedef void (*Proc)(const PtProcRec&, const SkPoint devPts[], int count, 303 SkBlitter*); 304 305 bool init(SkCanvas::PointMode, const SkPaint&, const SkMatrix* matrix, 306 const SkRasterClip*); 307 Proc chooseProc(SkBlitter** blitter); 308 309private: 310 SkAAClipBlitterWrapper fWrapper; 311}; 312 313static void bw_pt_rect_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 314 int count, SkBlitter* blitter) { 315 SkASSERT(rec.fClip->isRect()); 316 const SkIRect& r = rec.fClip->getBounds(); 317 318 for (int i = 0; i < count; i++) { 319 int x = SkScalarFloorToInt(devPts[i].fX); 320 int y = SkScalarFloorToInt(devPts[i].fY); 321 if (r.contains(x, y)) { 322 blitter->blitH(x, y, 1); 323 } 324 } 325} 326 327static void bw_pt_rect_16_hair_proc(const PtProcRec& rec, 328 const SkPoint devPts[], int count, 329 SkBlitter* blitter) { 330 SkASSERT(rec.fRC->isRect()); 331 const SkIRect& r = rec.fRC->getBounds(); 332 uint32_t value; 333 const SkPixmap* dst = blitter->justAnOpaqueColor(&value); 334 SkASSERT(dst); 335 336 uint16_t* addr = dst->writable_addr16(0, 0); 337 size_t rb = dst->rowBytes(); 338 339 for (int i = 0; i < count; i++) { 340 int x = SkScalarFloorToInt(devPts[i].fX); 341 int y = SkScalarFloorToInt(devPts[i].fY); 342 if (r.contains(x, y)) { 343 ((uint16_t*)((char*)addr + y * rb))[x] = SkToU16(value); 344 } 345 } 346} 347 348static void bw_pt_rect_32_hair_proc(const PtProcRec& rec, 349 const SkPoint devPts[], int count, 350 SkBlitter* blitter) { 351 SkASSERT(rec.fRC->isRect()); 352 const SkIRect& r = rec.fRC->getBounds(); 353 uint32_t value; 354 const SkPixmap* dst = blitter->justAnOpaqueColor(&value); 355 SkASSERT(dst); 356 357 SkPMColor* addr = dst->writable_addr32(0, 0); 358 size_t rb = dst->rowBytes(); 359 360 for (int i = 0; i < count; i++) { 361 int x = SkScalarFloorToInt(devPts[i].fX); 362 int y = SkScalarFloorToInt(devPts[i].fY); 363 if (r.contains(x, y)) { 364 ((SkPMColor*)((char*)addr + y * rb))[x] = value; 365 } 366 } 367} 368 369static void bw_pt_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 370 int count, SkBlitter* blitter) { 371 for (int i = 0; i < count; i++) { 372 int x = SkScalarFloorToInt(devPts[i].fX); 373 int y = SkScalarFloorToInt(devPts[i].fY); 374 if (rec.fClip->contains(x, y)) { 375 blitter->blitH(x, y, 1); 376 } 377 } 378} 379 380static void bw_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 381 int count, SkBlitter* blitter) { 382 for (int i = 0; i < count; i += 2) { 383 SkScan::HairLine(&devPts[i], 2, *rec.fRC, blitter); 384 } 385} 386 387static void bw_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 388 int count, SkBlitter* blitter) { 389 SkScan::HairLine(devPts, count, *rec.fRC, blitter); 390} 391 392// aa versions 393 394static void aa_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 395 int count, SkBlitter* blitter) { 396 for (int i = 0; i < count; i += 2) { 397 SkScan::AntiHairLine(&devPts[i], 2, *rec.fRC, blitter); 398 } 399} 400 401static void aa_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 402 int count, SkBlitter* blitter) { 403 SkScan::AntiHairLine(devPts, count, *rec.fRC, blitter); 404} 405 406// square procs (strokeWidth > 0 but matrix is square-scale (sx == sy) 407 408static void bw_square_proc(const PtProcRec& rec, const SkPoint devPts[], 409 int count, SkBlitter* blitter) { 410 const SkFixed radius = rec.fRadius; 411 for (int i = 0; i < count; i++) { 412 SkFixed x = SkScalarToFixed(devPts[i].fX); 413 SkFixed y = SkScalarToFixed(devPts[i].fY); 414 415 SkXRect r; 416 r.fLeft = x - radius; 417 r.fTop = y - radius; 418 r.fRight = x + radius; 419 r.fBottom = y + radius; 420 421 SkScan::FillXRect(r, *rec.fRC, blitter); 422 } 423} 424 425static void aa_square_proc(const PtProcRec& rec, const SkPoint devPts[], 426 int count, SkBlitter* blitter) { 427 const SkFixed radius = rec.fRadius; 428 for (int i = 0; i < count; i++) { 429 SkFixed x = SkScalarToFixed(devPts[i].fX); 430 SkFixed y = SkScalarToFixed(devPts[i].fY); 431 432 SkXRect r; 433 r.fLeft = x - radius; 434 r.fTop = y - radius; 435 r.fRight = x + radius; 436 r.fBottom = y + radius; 437 438 SkScan::AntiFillXRect(r, *rec.fRC, blitter); 439 } 440} 441 442// If this guy returns true, then chooseProc() must return a valid proc 443bool PtProcRec::init(SkCanvas::PointMode mode, const SkPaint& paint, 444 const SkMatrix* matrix, const SkRasterClip* rc) { 445 if ((unsigned)mode > (unsigned)SkCanvas::kPolygon_PointMode) { 446 return false; 447 } 448 449 if (paint.getPathEffect()) { 450 return false; 451 } 452 SkScalar width = paint.getStrokeWidth(); 453 if (0 == width) { 454 fMode = mode; 455 fPaint = &paint; 456 fClip = nullptr; 457 fRC = rc; 458 fRadius = SK_FixedHalf; 459 return true; 460 } 461 if (paint.getStrokeCap() != SkPaint::kRound_Cap && 462 matrix->isScaleTranslate() && SkCanvas::kPoints_PointMode == mode) { 463 SkScalar sx = matrix->get(SkMatrix::kMScaleX); 464 SkScalar sy = matrix->get(SkMatrix::kMScaleY); 465 if (SkScalarNearlyZero(sx - sy)) { 466 if (sx < 0) { 467 sx = -sx; 468 } 469 470 fMode = mode; 471 fPaint = &paint; 472 fClip = nullptr; 473 fRC = rc; 474 fRadius = SkScalarToFixed(SkScalarMul(width, sx)) >> 1; 475 return true; 476 } 477 } 478 return false; 479} 480 481PtProcRec::Proc PtProcRec::chooseProc(SkBlitter** blitterPtr) { 482 Proc proc = nullptr; 483 484 SkBlitter* blitter = *blitterPtr; 485 if (fRC->isBW()) { 486 fClip = &fRC->bwRgn(); 487 } else { 488 fWrapper.init(*fRC, blitter); 489 fClip = &fWrapper.getRgn(); 490 blitter = fWrapper.getBlitter(); 491 *blitterPtr = blitter; 492 } 493 494 // for our arrays 495 SkASSERT(0 == SkCanvas::kPoints_PointMode); 496 SkASSERT(1 == SkCanvas::kLines_PointMode); 497 SkASSERT(2 == SkCanvas::kPolygon_PointMode); 498 SkASSERT((unsigned)fMode <= (unsigned)SkCanvas::kPolygon_PointMode); 499 500 if (fPaint->isAntiAlias()) { 501 if (0 == fPaint->getStrokeWidth()) { 502 static const Proc gAAProcs[] = { 503 aa_square_proc, aa_line_hair_proc, aa_poly_hair_proc 504 }; 505 proc = gAAProcs[fMode]; 506 } else if (fPaint->getStrokeCap() != SkPaint::kRound_Cap) { 507 SkASSERT(SkCanvas::kPoints_PointMode == fMode); 508 proc = aa_square_proc; 509 } 510 } else { // BW 511 if (fRadius <= SK_FixedHalf) { // small radii and hairline 512 if (SkCanvas::kPoints_PointMode == fMode && fClip->isRect()) { 513 uint32_t value; 514 const SkPixmap* bm = blitter->justAnOpaqueColor(&value); 515 if (bm && kRGB_565_SkColorType == bm->colorType()) { 516 proc = bw_pt_rect_16_hair_proc; 517 } else if (bm && kN32_SkColorType == bm->colorType()) { 518 proc = bw_pt_rect_32_hair_proc; 519 } else { 520 proc = bw_pt_rect_hair_proc; 521 } 522 } else { 523 static Proc gBWProcs[] = { 524 bw_pt_hair_proc, bw_line_hair_proc, bw_poly_hair_proc 525 }; 526 proc = gBWProcs[fMode]; 527 } 528 } else { 529 proc = bw_square_proc; 530 } 531 } 532 return proc; 533} 534 535// each of these costs 8-bytes of stack space, so don't make it too large 536// must be even for lines/polygon to work 537#define MAX_DEV_PTS 32 538 539void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count, 540 const SkPoint pts[], const SkPaint& paint, 541 bool forceUseDevice) const { 542 // if we're in lines mode, force count to be even 543 if (SkCanvas::kLines_PointMode == mode) { 544 count &= ~(size_t)1; 545 } 546 547 if ((long)count <= 0) { 548 return; 549 } 550 551 SkASSERT(pts != nullptr); 552 SkDEBUGCODE(this->validate();) 553 554 // nothing to draw 555 if (fRC->isEmpty()) { 556 return; 557 } 558 559 PtProcRec rec; 560 if (!forceUseDevice && rec.init(mode, paint, fMatrix, fRC)) { 561 SkAutoBlitterChoose blitter(fDst, *fMatrix, paint); 562 563 SkPoint devPts[MAX_DEV_PTS]; 564 const SkMatrix* matrix = fMatrix; 565 SkBlitter* bltr = blitter.get(); 566 PtProcRec::Proc proc = rec.chooseProc(&bltr); 567 // we have to back up subsequent passes if we're in polygon mode 568 const size_t backup = (SkCanvas::kPolygon_PointMode == mode); 569 570 do { 571 int n = SkToInt(count); 572 if (n > MAX_DEV_PTS) { 573 n = MAX_DEV_PTS; 574 } 575 matrix->mapPoints(devPts, pts, n); 576 proc(rec, devPts, n, bltr); 577 pts += n - backup; 578 SkASSERT(SkToInt(count) >= n); 579 count -= n; 580 if (count > 0) { 581 count += backup; 582 } 583 } while (count != 0); 584 } else { 585 switch (mode) { 586 case SkCanvas::kPoints_PointMode: { 587 // temporarily mark the paint as filling. 588 SkPaint newPaint(paint); 589 newPaint.setStyle(SkPaint::kFill_Style); 590 591 SkScalar width = newPaint.getStrokeWidth(); 592 SkScalar radius = SkScalarHalf(width); 593 594 if (newPaint.getStrokeCap() == SkPaint::kRound_Cap) { 595 SkPath path; 596 SkMatrix preMatrix; 597 598 path.addCircle(0, 0, radius); 599 for (size_t i = 0; i < count; i++) { 600 preMatrix.setTranslate(pts[i].fX, pts[i].fY); 601 // pass true for the last point, since we can modify 602 // then path then 603 path.setIsVolatile((count-1) == i); 604 if (fDevice) { 605 fDevice->drawPath(*this, path, newPaint, &preMatrix, 606 (count-1) == i); 607 } else { 608 this->drawPath(path, newPaint, &preMatrix, 609 (count-1) == i); 610 } 611 } 612 } else { 613 SkRect r; 614 615 for (size_t i = 0; i < count; i++) { 616 r.fLeft = pts[i].fX - radius; 617 r.fTop = pts[i].fY - radius; 618 r.fRight = r.fLeft + width; 619 r.fBottom = r.fTop + width; 620 if (fDevice) { 621 fDevice->drawRect(*this, r, newPaint); 622 } else { 623 this->drawRect(r, newPaint); 624 } 625 } 626 } 627 break; 628 } 629 case SkCanvas::kLines_PointMode: 630 if (2 == count && paint.getPathEffect()) { 631 // most likely a dashed line - see if it is one of the ones 632 // we can accelerate 633 SkStrokeRec rec(paint); 634 SkPathEffect::PointData pointData; 635 636 SkPath path; 637 path.moveTo(pts[0]); 638 path.lineTo(pts[1]); 639 640 SkRect cullRect = SkRect::Make(fRC->getBounds()); 641 642 if (paint.getPathEffect()->asPoints(&pointData, path, rec, 643 *fMatrix, &cullRect)) { 644 // 'asPoints' managed to find some fast path 645 646 SkPaint newP(paint); 647 newP.setPathEffect(nullptr); 648 newP.setStyle(SkPaint::kFill_Style); 649 650 if (!pointData.fFirst.isEmpty()) { 651 if (fDevice) { 652 fDevice->drawPath(*this, pointData.fFirst, newP); 653 } else { 654 this->drawPath(pointData.fFirst, newP); 655 } 656 } 657 658 if (!pointData.fLast.isEmpty()) { 659 if (fDevice) { 660 fDevice->drawPath(*this, pointData.fLast, newP); 661 } else { 662 this->drawPath(pointData.fLast, newP); 663 } 664 } 665 666 if (pointData.fSize.fX == pointData.fSize.fY) { 667 // The rest of the dashed line can just be drawn as points 668 SkASSERT(pointData.fSize.fX == SkScalarHalf(newP.getStrokeWidth())); 669 670 if (SkPathEffect::PointData::kCircles_PointFlag & pointData.fFlags) { 671 newP.setStrokeCap(SkPaint::kRound_Cap); 672 } else { 673 newP.setStrokeCap(SkPaint::kButt_Cap); 674 } 675 676 if (fDevice) { 677 fDevice->drawPoints(*this, 678 SkCanvas::kPoints_PointMode, 679 pointData.fNumPoints, 680 pointData.fPoints, 681 newP); 682 } else { 683 this->drawPoints(SkCanvas::kPoints_PointMode, 684 pointData.fNumPoints, 685 pointData.fPoints, 686 newP, 687 forceUseDevice); 688 } 689 break; 690 } else { 691 // The rest of the dashed line must be drawn as rects 692 SkASSERT(!(SkPathEffect::PointData::kCircles_PointFlag & 693 pointData.fFlags)); 694 695 SkRect r; 696 697 for (int i = 0; i < pointData.fNumPoints; ++i) { 698 r.set(pointData.fPoints[i].fX - pointData.fSize.fX, 699 pointData.fPoints[i].fY - pointData.fSize.fY, 700 pointData.fPoints[i].fX + pointData.fSize.fX, 701 pointData.fPoints[i].fY + pointData.fSize.fY); 702 if (fDevice) { 703 fDevice->drawRect(*this, r, newP); 704 } else { 705 this->drawRect(r, newP); 706 } 707 } 708 } 709 710 break; 711 } 712 } 713 // couldn't take fast path so fall through! 714 case SkCanvas::kPolygon_PointMode: { 715 count -= 1; 716 SkPath path; 717 SkPaint p(paint); 718 p.setStyle(SkPaint::kStroke_Style); 719 size_t inc = (SkCanvas::kLines_PointMode == mode) ? 2 : 1; 720 path.setIsVolatile(true); 721 for (size_t i = 0; i < count; i += inc) { 722 path.moveTo(pts[i]); 723 path.lineTo(pts[i+1]); 724 if (fDevice) { 725 fDevice->drawPath(*this, path, p, nullptr, true); 726 } else { 727 this->drawPath(path, p, nullptr, true); 728 } 729 path.rewind(); 730 } 731 break; 732 } 733 } 734 } 735} 736 737static inline SkPoint compute_stroke_size(const SkPaint& paint, const SkMatrix& matrix) { 738 SkASSERT(matrix.rectStaysRect()); 739 SkASSERT(SkPaint::kFill_Style != paint.getStyle()); 740 741 SkVector size; 742 SkPoint pt = { paint.getStrokeWidth(), paint.getStrokeWidth() }; 743 matrix.mapVectors(&size, &pt, 1); 744 return SkPoint::Make(SkScalarAbs(size.fX), SkScalarAbs(size.fY)); 745} 746 747static bool easy_rect_join(const SkPaint& paint, const SkMatrix& matrix, 748 SkPoint* strokeSize) { 749 if (SkPaint::kMiter_Join != paint.getStrokeJoin() || 750 paint.getStrokeMiter() < SK_ScalarSqrt2) { 751 return false; 752 } 753 754 *strokeSize = compute_stroke_size(paint, matrix); 755 return true; 756} 757 758SkDraw::RectType SkDraw::ComputeRectType(const SkPaint& paint, 759 const SkMatrix& matrix, 760 SkPoint* strokeSize) { 761 RectType rtype; 762 const SkScalar width = paint.getStrokeWidth(); 763 const bool zeroWidth = (0 == width); 764 SkPaint::Style style = paint.getStyle(); 765 766 if ((SkPaint::kStrokeAndFill_Style == style) && zeroWidth) { 767 style = SkPaint::kFill_Style; 768 } 769 770 if (paint.getPathEffect() || paint.getMaskFilter() || 771 paint.getRasterizer() || !matrix.rectStaysRect() || 772 SkPaint::kStrokeAndFill_Style == style) { 773 rtype = kPath_RectType; 774 } else if (SkPaint::kFill_Style == style) { 775 rtype = kFill_RectType; 776 } else if (zeroWidth) { 777 rtype = kHair_RectType; 778 } else if (easy_rect_join(paint, matrix, strokeSize)) { 779 rtype = kStroke_RectType; 780 } else { 781 rtype = kPath_RectType; 782 } 783 return rtype; 784} 785 786static const SkPoint* rect_points(const SkRect& r) { 787 return SkTCast<const SkPoint*>(&r); 788} 789 790static SkPoint* rect_points(SkRect& r) { 791 return SkTCast<SkPoint*>(&r); 792} 793 794void SkDraw::drawRect(const SkRect& prePaintRect, const SkPaint& paint, 795 const SkMatrix* paintMatrix, const SkRect* postPaintRect) const { 796 SkDEBUGCODE(this->validate();) 797 798 // nothing to draw 799 if (fRC->isEmpty()) { 800 return; 801 } 802 803 const SkMatrix* matrix; 804 SkMatrix combinedMatrixStorage; 805 if (paintMatrix) { 806 SkASSERT(postPaintRect); 807 combinedMatrixStorage.setConcat(*fMatrix, *paintMatrix); 808 matrix = &combinedMatrixStorage; 809 } else { 810 SkASSERT(!postPaintRect); 811 matrix = fMatrix; 812 } 813 814 SkPoint strokeSize; 815 RectType rtype = ComputeRectType(paint, *fMatrix, &strokeSize); 816 817 if (kPath_RectType == rtype) { 818 SkDraw draw(*this); 819 if (paintMatrix) { 820 draw.fMatrix = matrix; 821 } 822 SkPath tmp; 823 tmp.addRect(prePaintRect); 824 tmp.setFillType(SkPath::kWinding_FillType); 825 draw.drawPath(tmp, paint, nullptr, true); 826 return; 827 } 828 829 SkRect devRect; 830 const SkRect& paintRect = paintMatrix ? *postPaintRect : prePaintRect; 831 // skip the paintMatrix when transforming the rect by the CTM 832 fMatrix->mapPoints(rect_points(devRect), rect_points(paintRect), 2); 833 devRect.sort(); 834 835 // look for the quick exit, before we build a blitter 836 SkRect bbox = devRect; 837 if (paint.getStyle() != SkPaint::kFill_Style) { 838 // extra space for hairlines 839 if (paint.getStrokeWidth() == 0) { 840 bbox.outset(1, 1); 841 } else { 842 // For kStroke_RectType, strokeSize is already computed. 843 const SkPoint& ssize = (kStroke_RectType == rtype) 844 ? strokeSize 845 : compute_stroke_size(paint, *fMatrix); 846 bbox.outset(SkScalarHalf(ssize.x()), SkScalarHalf(ssize.y())); 847 } 848 } 849 850 SkIRect ir = bbox.roundOut(); 851 if (fRC->quickReject(ir)) { 852 return; 853 } 854 855 SkDeviceLooper looper(fDst, *fRC, ir, paint.isAntiAlias()); 856 while (looper.next()) { 857 SkRect localDevRect; 858 looper.mapRect(&localDevRect, devRect); 859 SkMatrix localMatrix; 860 looper.mapMatrix(&localMatrix, *matrix); 861 862 SkAutoBlitterChoose blitterStorage(looper.getPixmap(), localMatrix, paint); 863 const SkRasterClip& clip = looper.getRC(); 864 SkBlitter* blitter = blitterStorage.get(); 865 866 // we want to "fill" if we are kFill or kStrokeAndFill, since in the latter 867 // case we are also hairline (if we've gotten to here), which devolves to 868 // effectively just kFill 869 switch (rtype) { 870 case kFill_RectType: 871 if (paint.isAntiAlias()) { 872 SkScan::AntiFillRect(localDevRect, clip, blitter); 873 } else { 874 SkScan::FillRect(localDevRect, clip, blitter); 875 } 876 break; 877 case kStroke_RectType: 878 if (paint.isAntiAlias()) { 879 SkScan::AntiFrameRect(localDevRect, strokeSize, clip, blitter); 880 } else { 881 SkScan::FrameRect(localDevRect, strokeSize, clip, blitter); 882 } 883 break; 884 case kHair_RectType: 885 if (paint.isAntiAlias()) { 886 SkScan::AntiHairRect(localDevRect, clip, blitter); 887 } else { 888 SkScan::HairRect(localDevRect, clip, blitter); 889 } 890 break; 891 default: 892 SkDEBUGFAIL("bad rtype"); 893 } 894 } 895} 896 897void SkDraw::drawDevMask(const SkMask& srcM, const SkPaint& paint) const { 898 if (srcM.fBounds.isEmpty()) { 899 return; 900 } 901 902 const SkMask* mask = &srcM; 903 904 SkMask dstM; 905 if (paint.getMaskFilter() && 906 paint.getMaskFilter()->filterMask(&dstM, srcM, *fMatrix, nullptr)) { 907 mask = &dstM; 908 } 909 SkAutoMaskFreeImage ami(dstM.fImage); 910 911 SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint); 912 SkBlitter* blitter = blitterChooser.get(); 913 914 SkAAClipBlitterWrapper wrapper; 915 const SkRegion* clipRgn; 916 917 if (fRC->isBW()) { 918 clipRgn = &fRC->bwRgn(); 919 } else { 920 wrapper.init(*fRC, blitter); 921 clipRgn = &wrapper.getRgn(); 922 blitter = wrapper.getBlitter(); 923 } 924 blitter->blitMaskRegion(*mask, *clipRgn); 925} 926 927static SkScalar fast_len(const SkVector& vec) { 928 SkScalar x = SkScalarAbs(vec.fX); 929 SkScalar y = SkScalarAbs(vec.fY); 930 if (x < y) { 931 SkTSwap(x, y); 932 } 933 return x + SkScalarHalf(y); 934} 935 936bool SkDrawTreatAAStrokeAsHairline(SkScalar strokeWidth, const SkMatrix& matrix, 937 SkScalar* coverage) { 938 SkASSERT(strokeWidth > 0); 939 // We need to try to fake a thick-stroke with a modulated hairline. 940 941 if (matrix.hasPerspective()) { 942 return false; 943 } 944 945 SkVector src[2], dst[2]; 946 src[0].set(strokeWidth, 0); 947 src[1].set(0, strokeWidth); 948 matrix.mapVectors(dst, src, 2); 949 SkScalar len0 = fast_len(dst[0]); 950 SkScalar len1 = fast_len(dst[1]); 951 if (len0 <= SK_Scalar1 && len1 <= SK_Scalar1) { 952 if (coverage) { 953 *coverage = SkScalarAve(len0, len1); 954 } 955 return true; 956 } 957 return false; 958} 959 960void SkDraw::drawRRect(const SkRRect& rrect, const SkPaint& paint) const { 961 SkDEBUGCODE(this->validate()); 962 963 if (fRC->isEmpty()) { 964 return; 965 } 966 967 { 968 // TODO: Investigate optimizing these options. They are in the same 969 // order as SkDraw::drawPath, which handles each case. It may be 970 // that there is no way to optimize for these using the SkRRect path. 971 SkScalar coverage; 972 if (SkDrawTreatAsHairline(paint, *fMatrix, &coverage)) { 973 goto DRAW_PATH; 974 } 975 976 if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) { 977 goto DRAW_PATH; 978 } 979 980 if (paint.getRasterizer()) { 981 goto DRAW_PATH; 982 } 983 } 984 985 if (paint.getMaskFilter()) { 986 // Transform the rrect into device space. 987 SkRRect devRRect; 988 if (rrect.transform(*fMatrix, &devRRect)) { 989 SkAutoBlitterChoose blitter(fDst, *fMatrix, paint); 990 if (paint.getMaskFilter()->filterRRect(devRRect, *fMatrix, *fRC, blitter.get())) { 991 return; // filterRRect() called the blitter, so we're done 992 } 993 } 994 } 995 996DRAW_PATH: 997 // Now fall back to the default case of using a path. 998 SkPath path; 999 path.addRRect(rrect); 1000 this->drawPath(path, paint, nullptr, true); 1001} 1002 1003SkScalar SkDraw::ComputeResScaleForStroking(const SkMatrix& matrix) { 1004 if (!matrix.hasPerspective()) { 1005 SkScalar sx = SkPoint::Length(matrix[SkMatrix::kMScaleX], matrix[SkMatrix::kMSkewY]); 1006 SkScalar sy = SkPoint::Length(matrix[SkMatrix::kMSkewX], matrix[SkMatrix::kMScaleY]); 1007 if (SkScalarsAreFinite(sx, sy)) { 1008 SkScalar scale = SkTMax(sx, sy); 1009 if (scale > 0) { 1010 return scale; 1011 } 1012 } 1013 } 1014 return 1; 1015} 1016 1017void SkDraw::drawDevPath(const SkPath& devPath, const SkPaint& paint, bool drawCoverage, 1018 SkBlitter* customBlitter, bool doFill) const { 1019 // Do a conservative quick-reject test, since a looper or other modifier may have moved us 1020 // out of range. 1021 if (!devPath.isInverseFillType()) { 1022 // If we're a H or V line, our bounds will be empty. So we bloat here just so we don't 1023 // appear empty to the intersects call. This also gives us slop in case we're antialiasing 1024 SkRect pathBounds = devPath.getBounds().makeOutset(1, 1); 1025 1026 if (paint.getMaskFilter()) { 1027 paint.getMaskFilter()->computeFastBounds(pathBounds, &pathBounds); 1028 1029 // Need to outset the path to work-around a bug in blurmaskfilter. When that is fixed 1030 // we can remove this hack. See skbug.com/5542 1031 pathBounds.outset(7, 7); 1032 } 1033 1034 // Now compare against the clip's bounds 1035 if (!SkRect::Make(fRC->getBounds()).intersects(pathBounds)) { 1036 return; 1037 } 1038 } 1039 1040 SkBlitter* blitter = nullptr; 1041 SkAutoBlitterChoose blitterStorage; 1042 if (nullptr == customBlitter) { 1043 blitterStorage.choose(fDst, *fMatrix, paint, drawCoverage); 1044 blitter = blitterStorage.get(); 1045 } else { 1046 blitter = customBlitter; 1047 } 1048 1049 if (paint.getMaskFilter()) { 1050 SkStrokeRec::InitStyle style = doFill ? SkStrokeRec::kFill_InitStyle 1051 : SkStrokeRec::kHairline_InitStyle; 1052 if (paint.getMaskFilter()->filterPath(devPath, *fMatrix, *fRC, blitter, style)) { 1053 return; // filterPath() called the blitter, so we're done 1054 } 1055 } 1056 1057 void (*proc)(const SkPath&, const SkRasterClip&, SkBlitter*); 1058 if (doFill) { 1059 if (paint.isAntiAlias()) { 1060 proc = SkScan::AntiFillPath; 1061 } else { 1062 proc = SkScan::FillPath; 1063 } 1064 } else { // hairline 1065 if (paint.isAntiAlias()) { 1066 switch (paint.getStrokeCap()) { 1067 case SkPaint::kButt_Cap: 1068 proc = SkScan::AntiHairPath; 1069 break; 1070 case SkPaint::kSquare_Cap: 1071 proc = SkScan::AntiHairSquarePath; 1072 break; 1073 case SkPaint::kRound_Cap: 1074 proc = SkScan::AntiHairRoundPath; 1075 break; 1076 default: 1077 proc SK_INIT_TO_AVOID_WARNING; 1078 SkDEBUGFAIL("unknown paint cap type"); 1079 } 1080 } else { 1081 switch (paint.getStrokeCap()) { 1082 case SkPaint::kButt_Cap: 1083 proc = SkScan::HairPath; 1084 break; 1085 case SkPaint::kSquare_Cap: 1086 proc = SkScan::HairSquarePath; 1087 break; 1088 case SkPaint::kRound_Cap: 1089 proc = SkScan::HairRoundPath; 1090 break; 1091 default: 1092 proc SK_INIT_TO_AVOID_WARNING; 1093 SkDEBUGFAIL("unknown paint cap type"); 1094 } 1095 } 1096 } 1097 proc(devPath, *fRC, blitter); 1098} 1099 1100void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint, 1101 const SkMatrix* prePathMatrix, bool pathIsMutable, 1102 bool drawCoverage, SkBlitter* customBlitter) const { 1103 SkDEBUGCODE(this->validate();) 1104 1105 // nothing to draw 1106 if (fRC->isEmpty()) { 1107 return; 1108 } 1109 1110 SkPath* pathPtr = (SkPath*)&origSrcPath; 1111 bool doFill = true; 1112 SkPath tmpPath; 1113 SkMatrix tmpMatrix; 1114 const SkMatrix* matrix = fMatrix; 1115 tmpPath.setIsVolatile(true); 1116 1117 if (prePathMatrix) { 1118 if (origPaint.getPathEffect() || origPaint.getStyle() != SkPaint::kFill_Style || 1119 origPaint.getRasterizer()) { 1120 SkPath* result = pathPtr; 1121 1122 if (!pathIsMutable) { 1123 result = &tmpPath; 1124 pathIsMutable = true; 1125 } 1126 pathPtr->transform(*prePathMatrix, result); 1127 pathPtr = result; 1128 } else { 1129 tmpMatrix.setConcat(*matrix, *prePathMatrix); 1130 matrix = &tmpMatrix; 1131 } 1132 } 1133 // at this point we're done with prePathMatrix 1134 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;) 1135 1136 SkTCopyOnFirstWrite<SkPaint> paint(origPaint); 1137 1138 { 1139 SkScalar coverage; 1140 if (SkDrawTreatAsHairline(origPaint, *matrix, &coverage)) { 1141 if (SK_Scalar1 == coverage) { 1142 paint.writable()->setStrokeWidth(0); 1143 } else if (SkBlendMode_SupportsCoverageAsAlpha(origPaint.getBlendMode())) { 1144 U8CPU newAlpha; 1145#if 0 1146 newAlpha = SkToU8(SkScalarRoundToInt(coverage * 1147 origPaint.getAlpha())); 1148#else 1149 // this is the old technique, which we preserve for now so 1150 // we don't change previous results (testing) 1151 // the new way seems fine, its just (a tiny bit) different 1152 int scale = (int)SkScalarMul(coverage, 256); 1153 newAlpha = origPaint.getAlpha() * scale >> 8; 1154#endif 1155 SkPaint* writablePaint = paint.writable(); 1156 writablePaint->setStrokeWidth(0); 1157 writablePaint->setAlpha(newAlpha); 1158 } 1159 } 1160 } 1161 1162 if (paint->getPathEffect() || paint->getStyle() != SkPaint::kFill_Style) { 1163 SkRect cullRect; 1164 const SkRect* cullRectPtr = nullptr; 1165 if (this->computeConservativeLocalClipBounds(&cullRect)) { 1166 cullRectPtr = &cullRect; 1167 } 1168 doFill = paint->getFillPath(*pathPtr, &tmpPath, cullRectPtr, 1169 ComputeResScaleForStroking(*fMatrix)); 1170 pathPtr = &tmpPath; 1171 } 1172 1173 if (paint->getRasterizer()) { 1174 SkMask mask; 1175 if (paint->getRasterizer()->rasterize(*pathPtr, *matrix, 1176 &fRC->getBounds(), paint->getMaskFilter(), &mask, 1177 SkMask::kComputeBoundsAndRenderImage_CreateMode)) { 1178 this->drawDevMask(mask, *paint); 1179 SkMask::FreeImage(mask.fImage); 1180 } 1181 return; 1182 } 1183 1184 // avoid possibly allocating a new path in transform if we can 1185 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath; 1186 1187 // transform the path into device space 1188 pathPtr->transform(*matrix, devPathPtr); 1189 1190 this->drawDevPath(*devPathPtr, *paint, drawCoverage, customBlitter, doFill); 1191} 1192 1193void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap, const SkPaint& paint) const { 1194 SkASSERT(bitmap.colorType() == kAlpha_8_SkColorType); 1195 1196 if (SkTreatAsSprite(*fMatrix, bitmap.dimensions(), paint)) { 1197 int ix = SkScalarRoundToInt(fMatrix->getTranslateX()); 1198 int iy = SkScalarRoundToInt(fMatrix->getTranslateY()); 1199 1200 SkAutoPixmapUnlock result; 1201 if (!bitmap.requestLock(&result)) { 1202 return; 1203 } 1204 const SkPixmap& pmap = result.pixmap(); 1205 SkMask mask; 1206 mask.fBounds.set(ix, iy, ix + pmap.width(), iy + pmap.height()); 1207 mask.fFormat = SkMask::kA8_Format; 1208 mask.fRowBytes = SkToU32(pmap.rowBytes()); 1209 // fImage is typed as writable, but in this case it is used read-only 1210 mask.fImage = (uint8_t*)pmap.addr8(0, 0); 1211 1212 this->drawDevMask(mask, paint); 1213 } else { // need to xform the bitmap first 1214 SkRect r; 1215 SkMask mask; 1216 1217 r.set(0, 0, 1218 SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height())); 1219 fMatrix->mapRect(&r); 1220 r.round(&mask.fBounds); 1221 1222 // set the mask's bounds to the transformed bitmap-bounds, 1223 // clipped to the actual device 1224 { 1225 SkIRect devBounds; 1226 devBounds.set(0, 0, fDst.width(), fDst.height()); 1227 // need intersect(l, t, r, b) on irect 1228 if (!mask.fBounds.intersect(devBounds)) { 1229 return; 1230 } 1231 } 1232 1233 mask.fFormat = SkMask::kA8_Format; 1234 mask.fRowBytes = SkAlign4(mask.fBounds.width()); 1235 size_t size = mask.computeImageSize(); 1236 if (0 == size) { 1237 // the mask is too big to allocated, draw nothing 1238 return; 1239 } 1240 1241 // allocate (and clear) our temp buffer to hold the transformed bitmap 1242 SkAutoTMalloc<uint8_t> storage(size); 1243 mask.fImage = storage.get(); 1244 memset(mask.fImage, 0, size); 1245 1246 // now draw our bitmap(src) into mask(dst), transformed by the matrix 1247 { 1248 SkBitmap device; 1249 device.installPixels(SkImageInfo::MakeA8(mask.fBounds.width(), mask.fBounds.height()), 1250 mask.fImage, mask.fRowBytes); 1251 1252 SkCanvas c(device); 1253 // need the unclipped top/left for the translate 1254 c.translate(-SkIntToScalar(mask.fBounds.fLeft), 1255 -SkIntToScalar(mask.fBounds.fTop)); 1256 c.concat(*fMatrix); 1257 1258 // We can't call drawBitmap, or we'll infinitely recurse. Instead 1259 // we manually build a shader and draw that into our new mask 1260 SkPaint tmpPaint; 1261 tmpPaint.setFlags(paint.getFlags()); 1262 tmpPaint.setFilterQuality(paint.getFilterQuality()); 1263 SkAutoBitmapShaderInstall install(bitmap, tmpPaint); 1264 SkRect rr; 1265 rr.set(0, 0, SkIntToScalar(bitmap.width()), 1266 SkIntToScalar(bitmap.height())); 1267 c.drawRect(rr, install.paintWithShader()); 1268 } 1269 this->drawDevMask(mask, paint); 1270 } 1271} 1272 1273static bool clipped_out(const SkMatrix& m, const SkRasterClip& c, 1274 const SkRect& srcR) { 1275 SkRect dstR; 1276 m.mapRect(&dstR, srcR); 1277 return c.quickReject(dstR.roundOut()); 1278} 1279 1280static bool clipped_out(const SkMatrix& matrix, const SkRasterClip& clip, 1281 int width, int height) { 1282 SkRect r; 1283 r.set(0, 0, SkIntToScalar(width), SkIntToScalar(height)); 1284 return clipped_out(matrix, clip, r); 1285} 1286 1287static bool clipHandlesSprite(const SkRasterClip& clip, int x, int y, const SkPixmap& pmap) { 1288 return clip.isBW() || clip.quickContains(x, y, x + pmap.width(), y + pmap.height()); 1289} 1290 1291void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix, 1292 const SkRect* dstBounds, const SkPaint& origPaint) const { 1293 SkDEBUGCODE(this->validate();) 1294 1295 // nothing to draw 1296 if (fRC->isEmpty() || 1297 bitmap.width() == 0 || bitmap.height() == 0 || 1298 bitmap.colorType() == kUnknown_SkColorType) { 1299 return; 1300 } 1301 1302 SkTCopyOnFirstWrite<SkPaint> paint(origPaint); 1303 if (origPaint.getStyle() != SkPaint::kFill_Style) { 1304 paint.writable()->setStyle(SkPaint::kFill_Style); 1305 } 1306 1307 SkMatrix matrix; 1308 matrix.setConcat(*fMatrix, prematrix); 1309 1310 if (clipped_out(matrix, *fRC, bitmap.width(), bitmap.height())) { 1311 return; 1312 } 1313 1314 if (bitmap.colorType() != kAlpha_8_SkColorType 1315 && SkTreatAsSprite(matrix, bitmap.dimensions(), *paint)) { 1316 // 1317 // It is safe to call lock pixels now, since we know the matrix is 1318 // (more or less) identity. 1319 // 1320 SkAutoPixmapUnlock unlocker; 1321 if (!bitmap.requestLock(&unlocker)) { 1322 return; 1323 } 1324 const SkPixmap& pmap = unlocker.pixmap(); 1325 int ix = SkScalarRoundToInt(matrix.getTranslateX()); 1326 int iy = SkScalarRoundToInt(matrix.getTranslateY()); 1327 if (clipHandlesSprite(*fRC, ix, iy, pmap)) { 1328 SkTBlitterAllocator allocator; 1329 // blitter will be owned by the allocator. 1330 SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, *paint, pmap, ix, iy, &allocator); 1331 if (blitter) { 1332 SkScan::FillIRect(SkIRect::MakeXYWH(ix, iy, pmap.width(), pmap.height()), 1333 *fRC, blitter); 1334 return; 1335 } 1336 // if !blitter, then we fall-through to the slower case 1337 } 1338 } 1339 1340 // now make a temp draw on the stack, and use it 1341 // 1342 SkDraw draw(*this); 1343 draw.fMatrix = &matrix; 1344 1345 if (bitmap.colorType() == kAlpha_8_SkColorType) { 1346 draw.drawBitmapAsMask(bitmap, *paint); 1347 } else { 1348 SkAutoBitmapShaderInstall install(bitmap, *paint); 1349 const SkPaint& paintWithShader = install.paintWithShader(); 1350 const SkRect srcBounds = SkRect::MakeIWH(bitmap.width(), bitmap.height()); 1351 if (dstBounds) { 1352 this->drawRect(srcBounds, paintWithShader, &prematrix, dstBounds); 1353 } else { 1354 draw.drawRect(srcBounds, paintWithShader); 1355 } 1356 } 1357} 1358 1359void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& origPaint) const { 1360 SkDEBUGCODE(this->validate();) 1361 1362 // nothing to draw 1363 if (fRC->isEmpty() || 1364 bitmap.width() == 0 || bitmap.height() == 0 || 1365 bitmap.colorType() == kUnknown_SkColorType) { 1366 return; 1367 } 1368 1369 const SkIRect bounds = SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height()); 1370 1371 if (fRC->quickReject(bounds)) { 1372 return; // nothing to draw 1373 } 1374 1375 SkPaint paint(origPaint); 1376 paint.setStyle(SkPaint::kFill_Style); 1377 1378 SkAutoPixmapUnlock unlocker; 1379 if (!bitmap.requestLock(&unlocker)) { 1380 return; 1381 } 1382 const SkPixmap& pmap = unlocker.pixmap(); 1383 1384 if (nullptr == paint.getColorFilter() && clipHandlesSprite(*fRC, x, y, pmap)) { 1385 SkTBlitterAllocator allocator; 1386 // blitter will be owned by the allocator. 1387 SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, paint, pmap, x, y, &allocator); 1388 if (blitter) { 1389 SkScan::FillIRect(bounds, *fRC, blitter); 1390 return; 1391 } 1392 } 1393 1394 SkMatrix matrix; 1395 SkRect r; 1396 1397 // get a scalar version of our rect 1398 r.set(bounds); 1399 1400 // create shader with offset 1401 matrix.setTranslate(r.fLeft, r.fTop); 1402 SkAutoBitmapShaderInstall install(bitmap, paint, &matrix); 1403 const SkPaint& shaderPaint = install.paintWithShader(); 1404 1405 SkDraw draw(*this); 1406 matrix.reset(); 1407 draw.fMatrix = &matrix; 1408 // call ourself with a rect 1409 // is this OK if paint has a rasterizer? 1410 draw.drawRect(r, shaderPaint); 1411} 1412 1413/////////////////////////////////////////////////////////////////////////////// 1414 1415#include "SkScalerContext.h" 1416#include "SkGlyphCache.h" 1417#include "SkTextToPathIter.h" 1418#include "SkUtils.h" 1419 1420bool SkDraw::ShouldDrawTextAsPaths(const SkPaint& paint, const SkMatrix& ctm) { 1421 // hairline glyphs are fast enough so we don't need to cache them 1422 if (SkPaint::kStroke_Style == paint.getStyle() && 0 == paint.getStrokeWidth()) { 1423 return true; 1424 } 1425 1426 // we don't cache perspective 1427 if (ctm.hasPerspective()) { 1428 return true; 1429 } 1430 1431 SkMatrix textM; 1432 return SkPaint::TooBigToUseCache(ctm, *paint.setTextMatrix(&textM)); 1433} 1434 1435void SkDraw::drawText_asPaths(const char text[], size_t byteLength, 1436 SkScalar x, SkScalar y, 1437 const SkPaint& paint) const { 1438 SkDEBUGCODE(this->validate();) 1439 1440 SkTextToPathIter iter(text, byteLength, paint, true); 1441 1442 SkMatrix matrix; 1443 matrix.setScale(iter.getPathScale(), iter.getPathScale()); 1444 matrix.postTranslate(x, y); 1445 1446 const SkPath* iterPath; 1447 SkScalar xpos, prevXPos = 0; 1448 1449 while (iter.next(&iterPath, &xpos)) { 1450 matrix.postTranslate(xpos - prevXPos, 0); 1451 if (iterPath) { 1452 const SkPaint& pnt = iter.getPaint(); 1453 if (fDevice) { 1454 fDevice->drawPath(*this, *iterPath, pnt, &matrix, false); 1455 } else { 1456 this->drawPath(*iterPath, pnt, &matrix, false); 1457 } 1458 } 1459 prevXPos = xpos; 1460 } 1461} 1462 1463// disable warning : local variable used without having been initialized 1464#if defined _WIN32 1465#pragma warning ( push ) 1466#pragma warning ( disable : 4701 ) 1467#endif 1468 1469//////////////////////////////////////////////////////////////////////////////////////////////////// 1470 1471class DrawOneGlyph { 1472public: 1473 DrawOneGlyph(const SkDraw& draw, const SkPaint& paint, SkGlyphCache* cache, SkBlitter* blitter) 1474 : fUseRegionToDraw(UsingRegionToDraw(draw.fRC)) 1475 , fGlyphCache(cache) 1476 , fBlitter(blitter) 1477 , fClip(fUseRegionToDraw ? &draw.fRC->bwRgn() : nullptr) 1478 , fDraw(draw) 1479 , fPaint(paint) 1480 , fClipBounds(PickClipBounds(draw)) { } 1481 1482 void operator()(const SkGlyph& glyph, SkPoint position, SkPoint rounding) { 1483 position += rounding; 1484 // Prevent glyphs from being drawn outside of or straddling the edge of device space. 1485 // Comparisons written a little weirdly so that NaN coordinates are treated safely. 1486 auto gt = [](float a, int b) { return !(a <= (float)b); }; 1487 auto lt = [](float a, int b) { return !(a >= (float)b); }; 1488 if (gt(position.fX, INT_MAX - (INT16_MAX + UINT16_MAX)) || 1489 lt(position.fX, INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/)) || 1490 gt(position.fY, INT_MAX - (INT16_MAX + UINT16_MAX)) || 1491 lt(position.fY, INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/))) { 1492 return; 1493 } 1494 1495 int left = SkScalarFloorToInt(position.fX); 1496 int top = SkScalarFloorToInt(position.fY); 1497 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0); 1498 1499 left += glyph.fLeft; 1500 top += glyph.fTop; 1501 1502 int right = left + glyph.fWidth; 1503 int bottom = top + glyph.fHeight; 1504 1505 SkMask mask; 1506 mask.fBounds.set(left, top, right, bottom); 1507 SkASSERT(!mask.fBounds.isEmpty()); 1508 1509 if (fUseRegionToDraw) { 1510 SkRegion::Cliperator clipper(*fClip, mask.fBounds); 1511 1512 if (!clipper.done() && this->getImageData(glyph, &mask)) { 1513 const SkIRect& cr = clipper.rect(); 1514 do { 1515 this->blitMask(mask, cr); 1516 clipper.next(); 1517 } while (!clipper.done()); 1518 } 1519 } else { 1520 SkIRect storage; 1521 SkIRect* bounds = &mask.fBounds; 1522 1523 // this extra test is worth it, assuming that most of the time it succeeds 1524 // since we can avoid writing to storage 1525 if (!fClipBounds.containsNoEmptyCheck(mask.fBounds)) { 1526 if (!storage.intersectNoEmptyCheck(mask.fBounds, fClipBounds)) 1527 return; 1528 bounds = &storage; 1529 } 1530 1531 if (this->getImageData(glyph, &mask)) { 1532 this->blitMask(mask, *bounds); 1533 } 1534 } 1535 } 1536 1537private: 1538 static bool UsingRegionToDraw(const SkRasterClip* rClip) { 1539 return rClip->isBW() && !rClip->isRect(); 1540 } 1541 1542 static SkIRect PickClipBounds(const SkDraw& draw) { 1543 const SkRasterClip& rasterClip = *draw.fRC; 1544 1545 if (rasterClip.isBW()) { 1546 return rasterClip.bwRgn().getBounds(); 1547 } else { 1548 return rasterClip.aaRgn().getBounds(); 1549 } 1550 } 1551 1552 bool getImageData(const SkGlyph& glyph, SkMask* mask) { 1553 uint8_t* bits = (uint8_t*)(fGlyphCache->findImage(glyph)); 1554 if (nullptr == bits) { 1555 return false; // can't rasterize glyph 1556 } 1557 mask->fImage = bits; 1558 mask->fRowBytes = glyph.rowBytes(); 1559 mask->fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat); 1560 return true; 1561 } 1562 1563 void blitMask(const SkMask& mask, const SkIRect& clip) const { 1564 if (SkMask::kARGB32_Format == mask.fFormat) { 1565 SkBitmap bm; 1566 bm.installPixels( 1567 SkImageInfo::MakeN32Premul(mask.fBounds.width(), mask.fBounds.height()), 1568 (SkPMColor*)mask.fImage, mask.fRowBytes); 1569 1570 fDraw.drawSprite(bm, mask.fBounds.x(), mask.fBounds.y(), fPaint); 1571 } else { 1572 fBlitter->blitMask(mask, clip); 1573 } 1574 } 1575 1576 const bool fUseRegionToDraw; 1577 SkGlyphCache * const fGlyphCache; 1578 SkBlitter * const fBlitter; 1579 const SkRegion* const fClip; 1580 const SkDraw& fDraw; 1581 const SkPaint& fPaint; 1582 const SkIRect fClipBounds; 1583}; 1584 1585//////////////////////////////////////////////////////////////////////////////////////////////////// 1586 1587uint32_t SkDraw::scalerContextFlags() const { 1588 uint32_t flags = SkPaint::kBoostContrast_ScalerContextFlag; 1589 if (!SkImageInfoIsGammaCorrect(fDevice->imageInfo())) { 1590 flags |= SkPaint::kFakeGamma_ScalerContextFlag; 1591 } 1592 return flags; 1593} 1594 1595void SkDraw::drawText(const char text[], size_t byteLength, 1596 SkScalar x, SkScalar y, const SkPaint& paint) const { 1597 SkASSERT(byteLength == 0 || text != nullptr); 1598 1599 SkDEBUGCODE(this->validate();) 1600 1601 // nothing to draw 1602 if (text == nullptr || byteLength == 0 || fRC->isEmpty()) { 1603 return; 1604 } 1605 1606 // SkScalarRec doesn't currently have a way of representing hairline stroke and 1607 // will fill if its frame-width is 0. 1608 if (ShouldDrawTextAsPaths(paint, *fMatrix)) { 1609 this->drawText_asPaths(text, byteLength, x, y, paint); 1610 return; 1611 } 1612 1613 SkAutoGlyphCache cache(paint, &fDevice->surfaceProps(), this->scalerContextFlags(), fMatrix); 1614 1615 // The Blitter Choose needs to be live while using the blitter below. 1616 SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint); 1617 SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get()); 1618 DrawOneGlyph drawOneGlyph(*this, paint, cache.get(), wrapper.getBlitter()); 1619 1620 SkFindAndPlaceGlyph::ProcessText( 1621 paint.getTextEncoding(), text, byteLength, 1622 {x, y}, *fMatrix, paint.getTextAlign(), cache.get(), drawOneGlyph); 1623} 1624 1625////////////////////////////////////////////////////////////////////////////// 1626 1627void SkDraw::drawPosText_asPaths(const char text[], size_t byteLength, 1628 const SkScalar pos[], int scalarsPerPosition, 1629 const SkPoint& offset, const SkPaint& origPaint) const { 1630 // setup our std paint, in hopes of getting hits in the cache 1631 SkPaint paint(origPaint); 1632 SkScalar matrixScale = paint.setupForAsPaths(); 1633 1634 SkMatrix matrix; 1635 matrix.setScale(matrixScale, matrixScale); 1636 1637 // Temporarily jam in kFill, so we only ever ask for the raw outline from the cache. 1638 paint.setStyle(SkPaint::kFill_Style); 1639 paint.setPathEffect(nullptr); 1640 1641 SkPaint::GlyphCacheProc glyphCacheProc = SkPaint::GetGlyphCacheProc(paint.getTextEncoding(), 1642 paint.isDevKernText(), 1643 true); 1644 SkAutoGlyphCache cache(paint, &fDevice->surfaceProps(), this->scalerContextFlags(), nullptr); 1645 1646 const char* stop = text + byteLength; 1647 SkTextAlignProc alignProc(paint.getTextAlign()); 1648 SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition); 1649 1650 // Now restore the original settings, so we "draw" with whatever style/stroking. 1651 paint.setStyle(origPaint.getStyle()); 1652 paint.setPathEffect(sk_ref_sp(origPaint.getPathEffect())); 1653 1654 while (text < stop) { 1655 const SkGlyph& glyph = glyphCacheProc(cache.get(), &text); 1656 if (glyph.fWidth) { 1657 const SkPath* path = cache->findPath(glyph); 1658 if (path) { 1659 SkPoint tmsLoc; 1660 tmsProc(pos, &tmsLoc); 1661 SkPoint loc; 1662 alignProc(tmsLoc, glyph, &loc); 1663 1664 matrix[SkMatrix::kMTransX] = loc.fX; 1665 matrix[SkMatrix::kMTransY] = loc.fY; 1666 if (fDevice) { 1667 fDevice->drawPath(*this, *path, paint, &matrix, false); 1668 } else { 1669 this->drawPath(*path, paint, &matrix, false); 1670 } 1671 } 1672 } 1673 pos += scalarsPerPosition; 1674 } 1675} 1676 1677void SkDraw::drawPosText(const char text[], size_t byteLength, 1678 const SkScalar pos[], int scalarsPerPosition, 1679 const SkPoint& offset, const SkPaint& paint) const { 1680 SkASSERT(byteLength == 0 || text != nullptr); 1681 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); 1682 1683 SkDEBUGCODE(this->validate();) 1684 1685 // nothing to draw 1686 if (text == nullptr || byteLength == 0 || fRC->isEmpty()) { 1687 return; 1688 } 1689 1690 if (ShouldDrawTextAsPaths(paint, *fMatrix)) { 1691 this->drawPosText_asPaths(text, byteLength, pos, scalarsPerPosition, offset, paint); 1692 return; 1693 } 1694 1695 SkAutoGlyphCache cache(paint, &fDevice->surfaceProps(), this->scalerContextFlags(), fMatrix); 1696 1697 // The Blitter Choose needs to be live while using the blitter below. 1698 SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint); 1699 SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get()); 1700 DrawOneGlyph drawOneGlyph(*this, paint, cache.get(), wrapper.getBlitter()); 1701 SkPaint::Align textAlignment = paint.getTextAlign(); 1702 1703 SkFindAndPlaceGlyph::ProcessPosText( 1704 paint.getTextEncoding(), text, byteLength, 1705 offset, *fMatrix, pos, scalarsPerPosition, textAlignment, cache.get(), drawOneGlyph); 1706} 1707 1708#if defined _WIN32 1709#pragma warning ( pop ) 1710#endif 1711 1712/////////////////////////////////////////////////////////////////////////////// 1713 1714static SkScan::HairRCProc ChooseHairProc(bool doAntiAlias) { 1715 return doAntiAlias ? SkScan::AntiHairLine : SkScan::HairLine; 1716} 1717 1718static bool texture_to_matrix(const VertState& state, const SkPoint verts[], 1719 const SkPoint texs[], SkMatrix* matrix) { 1720 SkPoint src[3], dst[3]; 1721 1722 src[0] = texs[state.f0]; 1723 src[1] = texs[state.f1]; 1724 src[2] = texs[state.f2]; 1725 dst[0] = verts[state.f0]; 1726 dst[1] = verts[state.f1]; 1727 dst[2] = verts[state.f2]; 1728 return matrix->setPolyToPoly(src, dst, 3); 1729} 1730 1731class SkTriColorShader : public SkShader { 1732public: 1733 SkTriColorShader(); 1734 1735 class TriColorShaderContext : public SkShader::Context { 1736 public: 1737 TriColorShaderContext(const SkTriColorShader& shader, const ContextRec&); 1738 virtual ~TriColorShaderContext(); 1739 void shadeSpan(int x, int y, SkPMColor dstC[], int count) override; 1740 1741 private: 1742 bool setup(const SkPoint pts[], const SkColor colors[], int, int, int); 1743 1744 SkMatrix fDstToUnit; 1745 SkPMColor fColors[3]; 1746 bool fSetup; 1747 1748 typedef SkShader::Context INHERITED; 1749 }; 1750 1751 struct TriColorShaderData { 1752 const SkPoint* pts; 1753 const SkColor* colors; 1754 const VertState *state; 1755 }; 1756 1757 SK_TO_STRING_OVERRIDE() 1758 1759 // For serialization. This will never be called. 1760 Factory getFactory() const override { sk_throw(); return nullptr; } 1761 1762 // Supply setup data to context from drawing setup 1763 void bindSetupData(TriColorShaderData* setupData) { fSetupData = setupData; } 1764 1765 // Take the setup data from context when needed. 1766 TriColorShaderData* takeSetupData() { 1767 TriColorShaderData *data = fSetupData; 1768 fSetupData = NULL; 1769 return data; 1770 } 1771 1772protected: 1773 size_t onContextSize(const ContextRec&) const override; 1774 Context* onCreateContext(const ContextRec& rec, void* storage) const override { 1775 return new (storage) TriColorShaderContext(*this, rec); 1776 } 1777 1778private: 1779 TriColorShaderData *fSetupData; 1780 1781 typedef SkShader INHERITED; 1782}; 1783 1784bool SkTriColorShader::TriColorShaderContext::setup(const SkPoint pts[], const SkColor colors[], 1785 int index0, int index1, int index2) { 1786 1787 fColors[0] = SkPreMultiplyColor(colors[index0]); 1788 fColors[1] = SkPreMultiplyColor(colors[index1]); 1789 fColors[2] = SkPreMultiplyColor(colors[index2]); 1790 1791 SkMatrix m, im; 1792 m.reset(); 1793 m.set(0, pts[index1].fX - pts[index0].fX); 1794 m.set(1, pts[index2].fX - pts[index0].fX); 1795 m.set(2, pts[index0].fX); 1796 m.set(3, pts[index1].fY - pts[index0].fY); 1797 m.set(4, pts[index2].fY - pts[index0].fY); 1798 m.set(5, pts[index0].fY); 1799 if (!m.invert(&im)) { 1800 return false; 1801 } 1802 // We can't call getTotalInverse(), because we explicitly don't want to look at the localmatrix 1803 // as our interators are intrinsically tied to the vertices, and nothing else. 1804 SkMatrix ctmInv; 1805 if (!this->getCTM().invert(&ctmInv)) { 1806 return false; 1807 } 1808 // TODO replace INV(m) * INV(ctm) with INV(ctm * m) 1809 fDstToUnit.setConcat(im, ctmInv); 1810 return true; 1811} 1812 1813#include "SkColorPriv.h" 1814#include "SkComposeShader.h" 1815 1816static int ScalarTo256(SkScalar v) { 1817 return static_cast<int>(SkScalarPin(v, 0, 1) * 256 + 0.5); 1818} 1819 1820SkTriColorShader::SkTriColorShader() 1821 : INHERITED(NULL) 1822 , fSetupData(NULL) {} 1823 1824SkTriColorShader::TriColorShaderContext::TriColorShaderContext(const SkTriColorShader& shader, 1825 const ContextRec& rec) 1826 : INHERITED(shader, rec) 1827 , fSetup(false) {} 1828 1829SkTriColorShader::TriColorShaderContext::~TriColorShaderContext() {} 1830 1831size_t SkTriColorShader::onContextSize(const ContextRec&) const { 1832 return sizeof(TriColorShaderContext); 1833} 1834 1835void SkTriColorShader::TriColorShaderContext::shadeSpan(int x, int y, SkPMColor dstC[], int count) { 1836 SkTriColorShader* parent = static_cast<SkTriColorShader*>(const_cast<SkShader*>(&fShader)); 1837 TriColorShaderData* set = parent->takeSetupData(); 1838 if (set) { 1839 fSetup = setup(set->pts, set->colors, set->state->f0, set->state->f1, set->state->f2); 1840 } 1841 1842 if (!fSetup) { 1843 // Invalid matrices. Not checked before so no need to assert. 1844 return; 1845 } 1846 1847 const int alphaScale = Sk255To256(this->getPaintAlpha()); 1848 1849 SkPoint src; 1850 1851 for (int i = 0; i < count; i++) { 1852 fDstToUnit.mapXY(SkIntToScalar(x), SkIntToScalar(y), &src); 1853 x += 1; 1854 1855 int scale1 = ScalarTo256(src.fX); 1856 int scale2 = ScalarTo256(src.fY); 1857 int scale0 = 256 - scale1 - scale2; 1858 if (scale0 < 0) { 1859 if (scale1 > scale2) { 1860 scale2 = 256 - scale1; 1861 } else { 1862 scale1 = 256 - scale2; 1863 } 1864 scale0 = 0; 1865 } 1866 1867 if (256 != alphaScale) { 1868 scale0 = SkAlphaMul(scale0, alphaScale); 1869 scale1 = SkAlphaMul(scale1, alphaScale); 1870 scale2 = SkAlphaMul(scale2, alphaScale); 1871 } 1872 1873 dstC[i] = SkAlphaMulQ(fColors[0], scale0) + 1874 SkAlphaMulQ(fColors[1], scale1) + 1875 SkAlphaMulQ(fColors[2], scale2); 1876 } 1877} 1878 1879#ifndef SK_IGNORE_TO_STRING 1880void SkTriColorShader::toString(SkString* str) const { 1881 str->append("SkTriColorShader: ("); 1882 1883 this->INHERITED::toString(str); 1884 1885 str->append(")"); 1886} 1887#endif 1888 1889void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count, 1890 const SkPoint vertices[], const SkPoint textures[], 1891 const SkColor colors[], SkXfermode* xmode, 1892 const uint16_t indices[], int indexCount, 1893 const SkPaint& paint) const { 1894 SkASSERT(0 == count || vertices); 1895 1896 // abort early if there is nothing to draw 1897 if (count < 3 || (indices && indexCount < 3) || fRC->isEmpty()) { 1898 return; 1899 } 1900 1901 // transform out vertices into device coordinates 1902 SkAutoSTMalloc<16, SkPoint> storage(count); 1903 SkPoint* devVerts = storage.get(); 1904 fMatrix->mapPoints(devVerts, vertices, count); 1905 1906 /* 1907 We can draw the vertices in 1 of 4 ways: 1908 1909 - solid color (no shader/texture[], no colors[]) 1910 - just colors (no shader/texture[], has colors[]) 1911 - just texture (has shader/texture[], no colors[]) 1912 - colors * texture (has shader/texture[], has colors[]) 1913 1914 Thus for texture drawing, we need both texture[] and a shader. 1915 */ 1916 1917 auto triShader = sk_make_sp<SkTriColorShader>(); 1918 SkPaint p(paint); 1919 1920 SkShader* shader = p.getShader(); 1921 if (nullptr == shader) { 1922 // if we have no shader, we ignore the texture coordinates 1923 textures = nullptr; 1924 } else if (nullptr == textures) { 1925 // if we don't have texture coordinates, ignore the shader 1926 p.setShader(nullptr); 1927 shader = nullptr; 1928 } 1929 1930 // setup the custom shader (if needed) 1931 if (colors) { 1932 if (nullptr == textures) { 1933 // just colors (no texture) 1934 p.setShader(triShader); 1935 } else { 1936 // colors * texture 1937 SkASSERT(shader); 1938 sk_sp<SkXfermode> xfer = xmode ? sk_ref_sp(xmode) 1939 : SkXfermode::Make(SkXfermode::kModulate_Mode); 1940 p.setShader(SkShader::MakeComposeShader(triShader, sk_ref_sp(shader), std::move(xfer))); 1941 } 1942 } 1943 1944 SkAutoBlitterChoose blitter(fDst, *fMatrix, p); 1945 // Abort early if we failed to create a shader context. 1946 if (blitter->isNullBlitter()) { 1947 return; 1948 } 1949 1950 // setup our state and function pointer for iterating triangles 1951 VertState state(count, indices, indexCount); 1952 VertState::Proc vertProc = state.chooseProc(vmode); 1953 1954 if (textures || colors) { 1955 SkTriColorShader::TriColorShaderData verticesSetup = { vertices, colors, &state }; 1956 1957 while (vertProc(&state)) { 1958 if (textures) { 1959 SkMatrix tempM; 1960 if (texture_to_matrix(state, vertices, textures, &tempM)) { 1961 SkShader::ContextRec rec(p, *fMatrix, &tempM, 1962 SkBlitter::PreferredShaderDest(fDst.info())); 1963 if (!blitter->resetShaderContext(rec)) { 1964 continue; 1965 } 1966 } 1967 } 1968 if (colors) { 1969 triShader->bindSetupData(&verticesSetup); 1970 } 1971 1972 SkPoint tmp[] = { 1973 devVerts[state.f0], devVerts[state.f1], devVerts[state.f2] 1974 }; 1975 SkScan::FillTriangle(tmp, *fRC, blitter.get()); 1976 triShader->bindSetupData(NULL); 1977 } 1978 } else { 1979 // no colors[] and no texture, stroke hairlines with paint's color. 1980 SkScan::HairRCProc hairProc = ChooseHairProc(paint.isAntiAlias()); 1981 const SkRasterClip& clip = *fRC; 1982 while (vertProc(&state)) { 1983 SkPoint array[] = { 1984 devVerts[state.f0], devVerts[state.f1], devVerts[state.f2], devVerts[state.f0] 1985 }; 1986 hairProc(array, 4, clip, blitter.get()); 1987 } 1988 } 1989} 1990 1991/////////////////////////////////////////////////////////////////////////////// 1992/////////////////////////////////////////////////////////////////////////////// 1993 1994#ifdef SK_DEBUG 1995 1996void SkDraw::validate() const { 1997 SkASSERT(fMatrix != nullptr); 1998 SkASSERT(fRC != nullptr); 1999 2000 const SkIRect& cr = fRC->getBounds(); 2001 SkIRect br; 2002 2003 br.set(0, 0, fDst.width(), fDst.height()); 2004 SkASSERT(cr.isEmpty() || br.contains(cr)); 2005} 2006 2007#endif 2008 2009//////////////////////////////////////////////////////////////////////////////////////////////// 2010 2011#include "SkPath.h" 2012#include "SkDraw.h" 2013#include "SkRegion.h" 2014#include "SkBlitter.h" 2015 2016static bool compute_bounds(const SkPath& devPath, const SkIRect* clipBounds, 2017 const SkMaskFilter* filter, const SkMatrix* filterMatrix, 2018 SkIRect* bounds) { 2019 if (devPath.isEmpty()) { 2020 return false; 2021 } 2022 2023 // init our bounds from the path 2024 *bounds = devPath.getBounds().makeOutset(SK_ScalarHalf, SK_ScalarHalf).roundOut(); 2025 2026 SkIPoint margin = SkIPoint::Make(0, 0); 2027 if (filter) { 2028 SkASSERT(filterMatrix); 2029 2030 SkMask srcM, dstM; 2031 2032 srcM.fBounds = *bounds; 2033 srcM.fFormat = SkMask::kA8_Format; 2034 if (!filter->filterMask(&dstM, srcM, *filterMatrix, &margin)) { 2035 return false; 2036 } 2037 } 2038 2039 // (possibly) trim the bounds to reflect the clip 2040 // (plus whatever slop the filter needs) 2041 if (clipBounds) { 2042 // Ugh. Guard against gigantic margins from wacky filters. Without this 2043 // check we can request arbitrary amounts of slop beyond our visible 2044 // clip, and bring down the renderer (at least on finite RAM machines 2045 // like handsets, etc.). Need to balance this invented value between 2046 // quality of large filters like blurs, and the corresponding memory 2047 // requests. 2048 static const int MAX_MARGIN = 128; 2049 if (!bounds->intersect(clipBounds->makeOutset(SkMin32(margin.fX, MAX_MARGIN), 2050 SkMin32(margin.fY, MAX_MARGIN)))) { 2051 return false; 2052 } 2053 } 2054 2055 return true; 2056} 2057 2058static void draw_into_mask(const SkMask& mask, const SkPath& devPath, 2059 SkStrokeRec::InitStyle style) { 2060 SkDraw draw; 2061 if (!draw.fDst.reset(mask)) { 2062 return; 2063 } 2064 2065 SkRasterClip clip; 2066 SkMatrix matrix; 2067 SkPaint paint; 2068 2069 clip.setRect(SkIRect::MakeWH(mask.fBounds.width(), mask.fBounds.height())); 2070 matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft), 2071 -SkIntToScalar(mask.fBounds.fTop)); 2072 2073 draw.fRC = &clip; 2074 draw.fMatrix = &matrix; 2075 paint.setAntiAlias(true); 2076 switch (style) { 2077 case SkStrokeRec::kHairline_InitStyle: 2078 SkASSERT(!paint.getStrokeWidth()); 2079 paint.setStyle(SkPaint::kStroke_Style); 2080 break; 2081 case SkStrokeRec::kFill_InitStyle: 2082 SkASSERT(paint.getStyle() == SkPaint::kFill_Style); 2083 break; 2084 2085 } 2086 draw.drawPath(devPath, paint); 2087} 2088 2089bool SkDraw::DrawToMask(const SkPath& devPath, const SkIRect* clipBounds, 2090 const SkMaskFilter* filter, const SkMatrix* filterMatrix, 2091 SkMask* mask, SkMask::CreateMode mode, 2092 SkStrokeRec::InitStyle style) { 2093 if (SkMask::kJustRenderImage_CreateMode != mode) { 2094 if (!compute_bounds(devPath, clipBounds, filter, filterMatrix, &mask->fBounds)) 2095 return false; 2096 } 2097 2098 if (SkMask::kComputeBoundsAndRenderImage_CreateMode == mode) { 2099 mask->fFormat = SkMask::kA8_Format; 2100 mask->fRowBytes = mask->fBounds.width(); 2101 size_t size = mask->computeImageSize(); 2102 if (0 == size) { 2103 // we're too big to allocate the mask, abort 2104 return false; 2105 } 2106 mask->fImage = SkMask::AllocImage(size); 2107 memset(mask->fImage, 0, mask->computeImageSize()); 2108 } 2109 2110 if (SkMask::kJustComputeBounds_CreateMode != mode) { 2111 draw_into_mask(*mask, devPath, style); 2112 } 2113 2114 return true; 2115} 2116