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