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