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