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