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