2 * Copyright 2006 The Android Open Source Project
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
7 #define __STDC_LIMIT_MACROS
10 #include "SkBlendModePriv.h"
11 #include "SkBlitter.h"
13 #include "SkColorPriv.h"
15 #include "SkDeviceLooper.h"
16 #include "SkFindAndPlaceGlyph.h"
18 #include "SkMaskFilter.h"
21 #include "SkPathEffect.h"
22 #include "SkRasterClip.h"
23 #include "SkRasterizer.h"
27 #include "SkSmallAllocator.h"
30 #include "SkStrokeRec.h"
31 #include "SkTemplates.h"
32 #include "SkTextMapStateProc.h"
35 #include "SkVertState.h"
36 #include "SkXfermode.h"
38 #include "SkBitmapProcShader.h"
39 #include "SkDrawProcs.h"
40 #include "SkMatrixUtils.h"
42 //#define TRACE_BITMAP_DRAWS
44 // Helper function to fix code gen bug on ARM64.
45 // See SkFindAndPlaceGlyph.h for more details.
46 void FixGCC49Arm64Bug(int v) { }
48 /** Helper for allocating small blitters on the stack.
50 class SkAutoBlitterChoose : SkNoncopyable {
52 SkAutoBlitterChoose() {
55 SkAutoBlitterChoose(const SkPixmap& dst, const SkMatrix& matrix,
56 const SkPaint& paint, bool drawCoverage = false) {
57 fBlitter = SkBlitter::Choose(dst, matrix, paint, &fAllocator, drawCoverage);
60 SkBlitter* operator->() { return fBlitter; }
61 SkBlitter* get() const { return fBlitter; }
63 void choose(const SkPixmap& dst, const SkMatrix& matrix,
64 const SkPaint& paint, bool drawCoverage = false) {
66 fBlitter = SkBlitter::Choose(dst, matrix, paint, &fAllocator, drawCoverage);
70 // Owned by fAllocator, which will handle the delete.
72 SkTBlitterAllocator fAllocator;
74 #define SkAutoBlitterChoose(...) SK_REQUIRE_LOCAL_VAR(SkAutoBlitterChoose)
77 * Since we are providing the storage for the shader (to avoid the perf cost
78 * of calling new) we insist that in our destructor we can account for all
79 * owners of the shader.
81 class SkAutoBitmapShaderInstall : SkNoncopyable {
83 SkAutoBitmapShaderInstall(const SkBitmap& src, const SkPaint& paint,
84 const SkMatrix* localMatrix = nullptr)
85 : fPaint(paint) /* makes a copy of the paint */ {
86 fPaint.setShader(SkMakeBitmapShader(src, SkShader::kClamp_TileMode,
87 SkShader::kClamp_TileMode, localMatrix,
88 kNever_SkCopyPixelsMode,
90 // we deliberately left the shader with an owner-count of 2
91 fPaint.getShader()->ref();
92 SkASSERT(2 == fPaint.getShader()->getRefCnt());
95 ~SkAutoBitmapShaderInstall() {
96 // since fAllocator will destroy shader, we insist that owners == 2
97 SkASSERT(2 == fPaint.getShader()->getRefCnt());
99 fPaint.setShader(nullptr); // unref the shader by 1
103 // return the new paint that has the shader applied
104 const SkPaint& paintWithShader() const { return fPaint; }
107 // copy of caller's paint (which we then modify)
109 // Stores the shader.
110 SkTBlitterAllocator fAllocator;
112 #define SkAutoBitmapShaderInstall(...) SK_REQUIRE_LOCAL_VAR(SkAutoBitmapShaderInstall)
114 ///////////////////////////////////////////////////////////////////////////////
117 sk_bzero(this, sizeof(*this));
120 bool SkDraw::computeConservativeLocalClipBounds(SkRect* localBounds) const {
121 if (fRC->isEmpty()) {
126 if (!fMatrix->invert(&inverse)) {
130 SkIRect devBounds = fRC->getBounds();
131 // outset to have slop for antialasing and hairlines
132 devBounds.outset(1, 1);
133 inverse.mapRect(localBounds, SkRect::Make(devBounds));
137 ///////////////////////////////////////////////////////////////////////////////
139 typedef void (*BitmapXferProc)(void* pixels, size_t bytes, uint32_t data);
141 static void D_Clear_BitmapXferProc(void* pixels, size_t bytes, uint32_t) {
142 sk_bzero(pixels, bytes);
145 static void D_Dst_BitmapXferProc(void*, size_t, uint32_t data) {}
147 static void D32_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) {
148 sk_memset32((uint32_t*)pixels, data, SkToInt(bytes >> 2));
151 static void D16_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) {
152 sk_memset16((uint16_t*)pixels, data, SkToInt(bytes >> 1));
155 static void DA8_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) {
156 memset(pixels, data, bytes);
159 static BitmapXferProc ChooseBitmapXferProc(const SkPixmap& dst, const SkPaint& paint,
161 // todo: we can apply colorfilter up front if no shader, so we wouldn't
162 // need to abort this fastpath
163 if (paint.getShader() || paint.getColorFilter()) {
167 SkBlendMode mode = paint.getBlendMode();
168 SkColor color = paint.getColor();
170 // collaps modes based on color...
171 if (SkBlendMode::kSrcOver == mode) {
172 unsigned alpha = SkColorGetA(color);
174 mode = SkBlendMode::kDst;
175 } else if (0xFF == alpha) {
176 mode = SkBlendMode::kSrc;
181 case SkBlendMode::kClear:
182 // SkDebugf("--- D_Clear_BitmapXferProc\n");
183 return D_Clear_BitmapXferProc; // ignore data
184 case SkBlendMode::kDst:
185 // SkDebugf("--- D_Dst_BitmapXferProc\n");
186 return D_Dst_BitmapXferProc; // ignore data
187 case SkBlendMode::kSrc: {
189 should I worry about dithering for the lower depths?
191 SkPMColor pmc = SkPreMultiplyColor(color);
192 switch (dst.colorType()) {
193 case kN32_SkColorType:
197 // SkDebugf("--- D32_Src_BitmapXferProc\n");
198 return D32_Src_BitmapXferProc;
199 case kRGB_565_SkColorType:
201 *data = SkPixel32ToPixel16(pmc);
203 // SkDebugf("--- D16_Src_BitmapXferProc\n");
204 return D16_Src_BitmapXferProc;
205 case kAlpha_8_SkColorType:
207 *data = SkGetPackedA32(pmc);
209 // SkDebugf("--- DA8_Src_BitmapXferProc\n");
210 return DA8_Src_BitmapXferProc;
222 static void CallBitmapXferProc(const SkPixmap& dst, const SkIRect& rect, BitmapXferProc proc,
225 switch (dst.colorType()) {
226 case kN32_SkColorType:
229 case kRGB_565_SkColorType:
232 case kAlpha_8_SkColorType:
236 SkDEBUGFAIL("Can't use xferproc on this config");
240 uint8_t* pixels = (uint8_t*)dst.writable_addr();
242 const size_t rowBytes = dst.rowBytes();
243 const int widthBytes = rect.width() << shiftPerPixel;
245 // skip down to the first scanline and X position
246 pixels += rect.fTop * rowBytes + (rect.fLeft << shiftPerPixel);
247 for (int scans = rect.height() - 1; scans >= 0; --scans) {
248 proc(pixels, widthBytes, procData);
253 void SkDraw::drawPaint(const SkPaint& paint) const {
254 SkDEBUGCODE(this->validate();)
256 if (fRC->isEmpty()) {
261 devRect.set(0, 0, fDst.width(), fDst.height());
264 /* If we don't have a shader (i.e. we're just a solid color) we may
265 be faster to operate directly on the device bitmap, rather than invoking
266 a blitter. Esp. true for xfermodes, which require a colorshader to be
267 present, which is just redundant work. Since we're drawing everywhere
268 in the clip, we don't have to worry about antialiasing.
270 uint32_t procData = 0; // to avoid the warning
271 BitmapXferProc proc = ChooseBitmapXferProc(fDst, paint, &procData);
273 if (D_Dst_BitmapXferProc == proc) { // nothing to do
277 SkRegion::Iterator iter(fRC->bwRgn());
278 while (!iter.done()) {
279 CallBitmapXferProc(fDst, iter.rect(), proc, procData);
286 // normal case: use a blitter
287 SkAutoBlitterChoose blitter(fDst, *fMatrix, paint);
288 SkScan::FillIRect(devRect, *fRC, blitter.get());
291 ///////////////////////////////////////////////////////////////////////////////
294 SkCanvas::PointMode fMode;
295 const SkPaint* fPaint;
296 const SkRegion* fClip;
297 const SkRasterClip* fRC;
302 typedef void (*Proc)(const PtProcRec&, const SkPoint devPts[], int count,
305 bool init(SkCanvas::PointMode, const SkPaint&, const SkMatrix* matrix,
306 const SkRasterClip*);
307 Proc chooseProc(SkBlitter** blitter);
310 SkAAClipBlitterWrapper fWrapper;
313 static void bw_pt_rect_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
314 int count, SkBlitter* blitter) {
315 SkASSERT(rec.fClip->isRect());
316 const SkIRect& r = rec.fClip->getBounds();
318 for (int i = 0; i < count; i++) {
319 int x = SkScalarFloorToInt(devPts[i].fX);
320 int y = SkScalarFloorToInt(devPts[i].fY);
321 if (r.contains(x, y)) {
322 blitter->blitH(x, y, 1);
327 static void bw_pt_rect_16_hair_proc(const PtProcRec& rec,
328 const SkPoint devPts[], int count,
329 SkBlitter* blitter) {
330 SkASSERT(rec.fRC->isRect());
331 const SkIRect& r = rec.fRC->getBounds();
333 const SkPixmap* dst = blitter->justAnOpaqueColor(&value);
336 uint16_t* addr = dst->writable_addr16(0, 0);
337 size_t rb = dst->rowBytes();
339 for (int i = 0; i < count; i++) {
340 int x = SkScalarFloorToInt(devPts[i].fX);
341 int y = SkScalarFloorToInt(devPts[i].fY);
342 if (r.contains(x, y)) {
343 ((uint16_t*)((char*)addr + y * rb))[x] = SkToU16(value);
348 static void bw_pt_rect_32_hair_proc(const PtProcRec& rec,
349 const SkPoint devPts[], int count,
350 SkBlitter* blitter) {
351 SkASSERT(rec.fRC->isRect());
352 const SkIRect& r = rec.fRC->getBounds();
354 const SkPixmap* dst = blitter->justAnOpaqueColor(&value);
357 SkPMColor* addr = dst->writable_addr32(0, 0);
358 size_t rb = dst->rowBytes();
360 for (int i = 0; i < count; i++) {
361 int x = SkScalarFloorToInt(devPts[i].fX);
362 int y = SkScalarFloorToInt(devPts[i].fY);
363 if (r.contains(x, y)) {
364 ((SkPMColor*)((char*)addr + y * rb))[x] = value;
369 static void bw_pt_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
370 int count, SkBlitter* blitter) {
371 for (int i = 0; i < count; i++) {
372 int x = SkScalarFloorToInt(devPts[i].fX);
373 int y = SkScalarFloorToInt(devPts[i].fY);
374 if (rec.fClip->contains(x, y)) {
375 blitter->blitH(x, y, 1);
380 static void bw_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
381 int count, SkBlitter* blitter) {
382 for (int i = 0; i < count; i += 2) {
383 SkScan::HairLine(&devPts[i], 2, *rec.fRC, blitter);
387 static void bw_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
388 int count, SkBlitter* blitter) {
389 SkScan::HairLine(devPts, count, *rec.fRC, blitter);
394 static void aa_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
395 int count, SkBlitter* blitter) {
396 for (int i = 0; i < count; i += 2) {
397 SkScan::AntiHairLine(&devPts[i], 2, *rec.fRC, blitter);
401 static void aa_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
402 int count, SkBlitter* blitter) {
403 SkScan::AntiHairLine(devPts, count, *rec.fRC, blitter);
406 // square procs (strokeWidth > 0 but matrix is square-scale (sx == sy)
408 static void bw_square_proc(const PtProcRec& rec, const SkPoint devPts[],
409 int count, SkBlitter* blitter) {
410 const SkFixed radius = rec.fRadius;
411 for (int i = 0; i < count; i++) {
412 SkFixed x = SkScalarToFixed(devPts[i].fX);
413 SkFixed y = SkScalarToFixed(devPts[i].fY);
416 r.fLeft = x - radius;
418 r.fRight = x + radius;
419 r.fBottom = y + radius;
421 SkScan::FillXRect(r, *rec.fRC, blitter);
425 static void aa_square_proc(const PtProcRec& rec, const SkPoint devPts[],
426 int count, SkBlitter* blitter) {
427 const SkFixed radius = rec.fRadius;
428 for (int i = 0; i < count; i++) {
429 SkFixed x = SkScalarToFixed(devPts[i].fX);
430 SkFixed y = SkScalarToFixed(devPts[i].fY);
433 r.fLeft = x - radius;
435 r.fRight = x + radius;
436 r.fBottom = y + radius;
438 SkScan::AntiFillXRect(r, *rec.fRC, blitter);
442 // If this guy returns true, then chooseProc() must return a valid proc
443 bool PtProcRec::init(SkCanvas::PointMode mode, const SkPaint& paint,
444 const SkMatrix* matrix, const SkRasterClip* rc) {
445 if ((unsigned)mode > (unsigned)SkCanvas::kPolygon_PointMode) {
449 if (paint.getPathEffect()) {
452 SkScalar width = paint.getStrokeWidth();
458 fRadius = SK_FixedHalf;
461 if (paint.getStrokeCap() != SkPaint::kRound_Cap &&
462 matrix->isScaleTranslate() && SkCanvas::kPoints_PointMode == mode) {
463 SkScalar sx = matrix->get(SkMatrix::kMScaleX);
464 SkScalar sy = matrix->get(SkMatrix::kMScaleY);
465 if (SkScalarNearlyZero(sx - sy)) {
474 fRadius = SkScalarToFixed(SkScalarMul(width, sx)) >> 1;
481 PtProcRec::Proc PtProcRec::chooseProc(SkBlitter** blitterPtr) {
484 SkBlitter* blitter = *blitterPtr;
486 fClip = &fRC->bwRgn();
488 fWrapper.init(*fRC, blitter);
489 fClip = &fWrapper.getRgn();
490 blitter = fWrapper.getBlitter();
491 *blitterPtr = blitter;
495 SkASSERT(0 == SkCanvas::kPoints_PointMode);
496 SkASSERT(1 == SkCanvas::kLines_PointMode);
497 SkASSERT(2 == SkCanvas::kPolygon_PointMode);
498 SkASSERT((unsigned)fMode <= (unsigned)SkCanvas::kPolygon_PointMode);
500 if (fPaint->isAntiAlias()) {
501 if (0 == fPaint->getStrokeWidth()) {
502 static const Proc gAAProcs[] = {
503 aa_square_proc, aa_line_hair_proc, aa_poly_hair_proc
505 proc = gAAProcs[fMode];
506 } else if (fPaint->getStrokeCap() != SkPaint::kRound_Cap) {
507 SkASSERT(SkCanvas::kPoints_PointMode == fMode);
508 proc = aa_square_proc;
511 if (fRadius <= SK_FixedHalf) { // small radii and hairline
512 if (SkCanvas::kPoints_PointMode == fMode && fClip->isRect()) {
514 const SkPixmap* bm = blitter->justAnOpaqueColor(&value);
515 if (bm && kRGB_565_SkColorType == bm->colorType()) {
516 proc = bw_pt_rect_16_hair_proc;
517 } else if (bm && kN32_SkColorType == bm->colorType()) {
518 proc = bw_pt_rect_32_hair_proc;
520 proc = bw_pt_rect_hair_proc;
523 static Proc gBWProcs[] = {
524 bw_pt_hair_proc, bw_line_hair_proc, bw_poly_hair_proc
526 proc = gBWProcs[fMode];
529 proc = bw_square_proc;
535 // each of these costs 8-bytes of stack space, so don't make it too large
536 // must be even for lines/polygon to work
537 #define MAX_DEV_PTS 32
539 void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count,
540 const SkPoint pts[], const SkPaint& paint,
541 bool forceUseDevice) const {
542 // if we're in lines mode, force count to be even
543 if (SkCanvas::kLines_PointMode == mode) {
547 if ((long)count <= 0) {
551 SkASSERT(pts != nullptr);
552 SkDEBUGCODE(this->validate();)
555 if (fRC->isEmpty()) {
560 if (!forceUseDevice && rec.init(mode, paint, fMatrix, fRC)) {
561 SkAutoBlitterChoose blitter(fDst, *fMatrix, paint);
563 SkPoint devPts[MAX_DEV_PTS];
564 const SkMatrix* matrix = fMatrix;
565 SkBlitter* bltr = blitter.get();
566 PtProcRec::Proc proc = rec.chooseProc(&bltr);
567 // we have to back up subsequent passes if we're in polygon mode
568 const size_t backup = (SkCanvas::kPolygon_PointMode == mode);
571 int n = SkToInt(count);
572 if (n > MAX_DEV_PTS) {
575 matrix->mapPoints(devPts, pts, n);
576 proc(rec, devPts, n, bltr);
578 SkASSERT(SkToInt(count) >= n);
583 } while (count != 0);
586 case SkCanvas::kPoints_PointMode: {
587 // temporarily mark the paint as filling.
588 SkPaint newPaint(paint);
589 newPaint.setStyle(SkPaint::kFill_Style);
591 SkScalar width = newPaint.getStrokeWidth();
592 SkScalar radius = SkScalarHalf(width);
594 if (newPaint.getStrokeCap() == SkPaint::kRound_Cap) {
598 path.addCircle(0, 0, radius);
599 for (size_t i = 0; i < count; i++) {
600 preMatrix.setTranslate(pts[i].fX, pts[i].fY);
601 // pass true for the last point, since we can modify
603 path.setIsVolatile((count-1) == i);
605 fDevice->drawPath(*this, path, newPaint, &preMatrix,
608 this->drawPath(path, newPaint, &preMatrix,
615 for (size_t i = 0; i < count; i++) {
616 r.fLeft = pts[i].fX - radius;
617 r.fTop = pts[i].fY - radius;
618 r.fRight = r.fLeft + width;
619 r.fBottom = r.fTop + width;
621 fDevice->drawRect(*this, r, newPaint);
623 this->drawRect(r, newPaint);
629 case SkCanvas::kLines_PointMode:
630 if (2 == count && paint.getPathEffect()) {
631 // most likely a dashed line - see if it is one of the ones
633 SkStrokeRec rec(paint);
634 SkPathEffect::PointData pointData;
640 SkRect cullRect = SkRect::Make(fRC->getBounds());
642 if (paint.getPathEffect()->asPoints(&pointData, path, rec,
643 *fMatrix, &cullRect)) {
644 // 'asPoints' managed to find some fast path
647 newP.setPathEffect(nullptr);
648 newP.setStyle(SkPaint::kFill_Style);
650 if (!pointData.fFirst.isEmpty()) {
652 fDevice->drawPath(*this, pointData.fFirst, newP);
654 this->drawPath(pointData.fFirst, newP);
658 if (!pointData.fLast.isEmpty()) {
660 fDevice->drawPath(*this, pointData.fLast, newP);
662 this->drawPath(pointData.fLast, newP);
666 if (pointData.fSize.fX == pointData.fSize.fY) {
667 // The rest of the dashed line can just be drawn as points
668 SkASSERT(pointData.fSize.fX == SkScalarHalf(newP.getStrokeWidth()));
670 if (SkPathEffect::PointData::kCircles_PointFlag & pointData.fFlags) {
671 newP.setStrokeCap(SkPaint::kRound_Cap);
673 newP.setStrokeCap(SkPaint::kButt_Cap);
677 fDevice->drawPoints(*this,
678 SkCanvas::kPoints_PointMode,
679 pointData.fNumPoints,
683 this->drawPoints(SkCanvas::kPoints_PointMode,
684 pointData.fNumPoints,
691 // The rest of the dashed line must be drawn as rects
692 SkASSERT(!(SkPathEffect::PointData::kCircles_PointFlag &
697 for (int i = 0; i < pointData.fNumPoints; ++i) {
698 r.set(pointData.fPoints[i].fX - pointData.fSize.fX,
699 pointData.fPoints[i].fY - pointData.fSize.fY,
700 pointData.fPoints[i].fX + pointData.fSize.fX,
701 pointData.fPoints[i].fY + pointData.fSize.fY);
703 fDevice->drawRect(*this, r, newP);
705 this->drawRect(r, newP);
713 // couldn't take fast path so fall through!
714 case SkCanvas::kPolygon_PointMode: {
718 p.setStyle(SkPaint::kStroke_Style);
719 size_t inc = (SkCanvas::kLines_PointMode == mode) ? 2 : 1;
720 path.setIsVolatile(true);
721 for (size_t i = 0; i < count; i += inc) {
723 path.lineTo(pts[i+1]);
725 fDevice->drawPath(*this, path, p, nullptr, true);
727 this->drawPath(path, p, nullptr, true);
737 static inline SkPoint compute_stroke_size(const SkPaint& paint, const SkMatrix& matrix) {
738 SkASSERT(matrix.rectStaysRect());
739 SkASSERT(SkPaint::kFill_Style != paint.getStyle());
742 SkPoint pt = { paint.getStrokeWidth(), paint.getStrokeWidth() };
743 matrix.mapVectors(&size, &pt, 1);
744 return SkPoint::Make(SkScalarAbs(size.fX), SkScalarAbs(size.fY));
747 static bool easy_rect_join(const SkPaint& paint, const SkMatrix& matrix,
748 SkPoint* strokeSize) {
749 if (SkPaint::kMiter_Join != paint.getStrokeJoin() ||
750 paint.getStrokeMiter() < SK_ScalarSqrt2) {
754 *strokeSize = compute_stroke_size(paint, matrix);
758 SkDraw::RectType SkDraw::ComputeRectType(const SkPaint& paint,
759 const SkMatrix& matrix,
760 SkPoint* strokeSize) {
762 const SkScalar width = paint.getStrokeWidth();
763 const bool zeroWidth = (0 == width);
764 SkPaint::Style style = paint.getStyle();
766 if ((SkPaint::kStrokeAndFill_Style == style) && zeroWidth) {
767 style = SkPaint::kFill_Style;
770 if (paint.getPathEffect() || paint.getMaskFilter() ||
771 paint.getRasterizer() || !matrix.rectStaysRect() ||
772 SkPaint::kStrokeAndFill_Style == style) {
773 rtype = kPath_RectType;
774 } else if (SkPaint::kFill_Style == style) {
775 rtype = kFill_RectType;
776 } else if (zeroWidth) {
777 rtype = kHair_RectType;
778 } else if (easy_rect_join(paint, matrix, strokeSize)) {
779 rtype = kStroke_RectType;
781 rtype = kPath_RectType;
786 static const SkPoint* rect_points(const SkRect& r) {
787 return SkTCast<const SkPoint*>(&r);
790 static SkPoint* rect_points(SkRect& r) {
791 return SkTCast<SkPoint*>(&r);
794 void SkDraw::drawRect(const SkRect& prePaintRect, const SkPaint& paint,
795 const SkMatrix* paintMatrix, const SkRect* postPaintRect) const {
796 SkDEBUGCODE(this->validate();)
799 if (fRC->isEmpty()) {
803 const SkMatrix* matrix;
804 SkMatrix combinedMatrixStorage;
806 SkASSERT(postPaintRect);
807 combinedMatrixStorage.setConcat(*fMatrix, *paintMatrix);
808 matrix = &combinedMatrixStorage;
810 SkASSERT(!postPaintRect);
815 RectType rtype = ComputeRectType(paint, *fMatrix, &strokeSize);
817 if (kPath_RectType == rtype) {
820 draw.fMatrix = matrix;
823 tmp.addRect(prePaintRect);
824 tmp.setFillType(SkPath::kWinding_FillType);
825 draw.drawPath(tmp, paint, nullptr, true);
830 const SkRect& paintRect = paintMatrix ? *postPaintRect : prePaintRect;
831 // skip the paintMatrix when transforming the rect by the CTM
832 fMatrix->mapPoints(rect_points(devRect), rect_points(paintRect), 2);
835 // look for the quick exit, before we build a blitter
836 SkRect bbox = devRect;
837 if (paint.getStyle() != SkPaint::kFill_Style) {
838 // extra space for hairlines
839 if (paint.getStrokeWidth() == 0) {
842 // For kStroke_RectType, strokeSize is already computed.
843 const SkPoint& ssize = (kStroke_RectType == rtype)
845 : compute_stroke_size(paint, *fMatrix);
846 bbox.outset(SkScalarHalf(ssize.x()), SkScalarHalf(ssize.y()));
850 SkIRect ir = bbox.roundOut();
851 if (fRC->quickReject(ir)) {
855 SkDeviceLooper looper(fDst, *fRC, ir, paint.isAntiAlias());
856 while (looper.next()) {
858 looper.mapRect(&localDevRect, devRect);
859 SkMatrix localMatrix;
860 looper.mapMatrix(&localMatrix, *matrix);
862 SkAutoBlitterChoose blitterStorage(looper.getPixmap(), localMatrix, paint);
863 const SkRasterClip& clip = looper.getRC();
864 SkBlitter* blitter = blitterStorage.get();
866 // we want to "fill" if we are kFill or kStrokeAndFill, since in the latter
867 // case we are also hairline (if we've gotten to here), which devolves to
868 // effectively just kFill
871 if (paint.isAntiAlias()) {
872 SkScan::AntiFillRect(localDevRect, clip, blitter);
874 SkScan::FillRect(localDevRect, clip, blitter);
877 case kStroke_RectType:
878 if (paint.isAntiAlias()) {
879 SkScan::AntiFrameRect(localDevRect, strokeSize, clip, blitter);
881 SkScan::FrameRect(localDevRect, strokeSize, clip, blitter);
885 if (paint.isAntiAlias()) {
886 SkScan::AntiHairRect(localDevRect, clip, blitter);
888 SkScan::HairRect(localDevRect, clip, blitter);
892 SkDEBUGFAIL("bad rtype");
897 void SkDraw::drawDevMask(const SkMask& srcM, const SkPaint& paint) const {
898 if (srcM.fBounds.isEmpty()) {
902 const SkMask* mask = &srcM;
905 if (paint.getMaskFilter() &&
906 paint.getMaskFilter()->filterMask(&dstM, srcM, *fMatrix, nullptr)) {
909 SkAutoMaskFreeImage ami(dstM.fImage);
911 SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint);
912 SkBlitter* blitter = blitterChooser.get();
914 SkAAClipBlitterWrapper wrapper;
915 const SkRegion* clipRgn;
918 clipRgn = &fRC->bwRgn();
920 wrapper.init(*fRC, blitter);
921 clipRgn = &wrapper.getRgn();
922 blitter = wrapper.getBlitter();
924 blitter->blitMaskRegion(*mask, *clipRgn);
927 static SkScalar fast_len(const SkVector& vec) {
928 SkScalar x = SkScalarAbs(vec.fX);
929 SkScalar y = SkScalarAbs(vec.fY);
933 return x + SkScalarHalf(y);
936 bool SkDrawTreatAAStrokeAsHairline(SkScalar strokeWidth, const SkMatrix& matrix,
937 SkScalar* coverage) {
938 SkASSERT(strokeWidth > 0);
939 // We need to try to fake a thick-stroke with a modulated hairline.
941 if (matrix.hasPerspective()) {
945 SkVector src[2], dst[2];
946 src[0].set(strokeWidth, 0);
947 src[1].set(0, strokeWidth);
948 matrix.mapVectors(dst, src, 2);
949 SkScalar len0 = fast_len(dst[0]);
950 SkScalar len1 = fast_len(dst[1]);
951 if (len0 <= SK_Scalar1 && len1 <= SK_Scalar1) {
953 *coverage = SkScalarAve(len0, len1);
960 void SkDraw::drawRRect(const SkRRect& rrect, const SkPaint& paint) const {
961 SkDEBUGCODE(this->validate());
963 if (fRC->isEmpty()) {
968 // TODO: Investigate optimizing these options. They are in the same
969 // order as SkDraw::drawPath, which handles each case. It may be
970 // that there is no way to optimize for these using the SkRRect path.
972 if (SkDrawTreatAsHairline(paint, *fMatrix, &coverage)) {
976 if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) {
980 if (paint.getRasterizer()) {
985 if (paint.getMaskFilter()) {
986 // Transform the rrect into device space.
988 if (rrect.transform(*fMatrix, &devRRect)) {
989 SkAutoBlitterChoose blitter(fDst, *fMatrix, paint);
990 if (paint.getMaskFilter()->filterRRect(devRRect, *fMatrix, *fRC, blitter.get())) {
991 return; // filterRRect() called the blitter, so we're done
997 // Now fall back to the default case of using a path.
999 path.addRRect(rrect);
1000 this->drawPath(path, paint, nullptr, true);
1003 SkScalar SkDraw::ComputeResScaleForStroking(const SkMatrix& matrix) {
1004 if (!matrix.hasPerspective()) {
1005 SkScalar sx = SkPoint::Length(matrix[SkMatrix::kMScaleX], matrix[SkMatrix::kMSkewY]);
1006 SkScalar sy = SkPoint::Length(matrix[SkMatrix::kMSkewX], matrix[SkMatrix::kMScaleY]);
1007 if (SkScalarsAreFinite(sx, sy)) {
1008 SkScalar scale = SkTMax(sx, sy);
1017 void SkDraw::drawDevPath(const SkPath& devPath, const SkPaint& paint, bool drawCoverage,
1018 SkBlitter* customBlitter, bool doFill) const {
1019 // Do a conservative quick-reject test, since a looper or other modifier may have moved us
1021 if (!devPath.isInverseFillType()) {
1022 // If we're a H or V line, our bounds will be empty. So we bloat here just so we don't
1023 // appear empty to the intersects call. This also gives us slop in case we're antialiasing
1024 SkRect pathBounds = devPath.getBounds().makeOutset(1, 1);
1026 if (paint.getMaskFilter()) {
1027 paint.getMaskFilter()->computeFastBounds(pathBounds, &pathBounds);
1029 // Need to outset the path to work-around a bug in blurmaskfilter. When that is fixed
1030 // we can remove this hack. See skbug.com/5542
1031 pathBounds.outset(7, 7);
1034 // Now compare against the clip's bounds
1035 if (!SkRect::Make(fRC->getBounds()).intersects(pathBounds)) {
1040 SkBlitter* blitter = nullptr;
1041 SkAutoBlitterChoose blitterStorage;
1042 if (nullptr == customBlitter) {
1043 blitterStorage.choose(fDst, *fMatrix, paint, drawCoverage);
1044 blitter = blitterStorage.get();
1046 blitter = customBlitter;
1049 if (paint.getMaskFilter()) {
1050 SkStrokeRec::InitStyle style = doFill ? SkStrokeRec::kFill_InitStyle
1051 : SkStrokeRec::kHairline_InitStyle;
1052 if (paint.getMaskFilter()->filterPath(devPath, *fMatrix, *fRC, blitter, style)) {
1053 return; // filterPath() called the blitter, so we're done
1057 void (*proc)(const SkPath&, const SkRasterClip&, SkBlitter*);
1059 if (paint.isAntiAlias()) {
1060 proc = SkScan::AntiFillPath;
1062 proc = SkScan::FillPath;
1064 } else { // hairline
1065 if (paint.isAntiAlias()) {
1066 switch (paint.getStrokeCap()) {
1067 case SkPaint::kButt_Cap:
1068 proc = SkScan::AntiHairPath;
1070 case SkPaint::kSquare_Cap:
1071 proc = SkScan::AntiHairSquarePath;
1073 case SkPaint::kRound_Cap:
1074 proc = SkScan::AntiHairRoundPath;
1077 proc SK_INIT_TO_AVOID_WARNING;
1078 SkDEBUGFAIL("unknown paint cap type");
1081 switch (paint.getStrokeCap()) {
1082 case SkPaint::kButt_Cap:
1083 proc = SkScan::HairPath;
1085 case SkPaint::kSquare_Cap:
1086 proc = SkScan::HairSquarePath;
1088 case SkPaint::kRound_Cap:
1089 proc = SkScan::HairRoundPath;
1092 proc SK_INIT_TO_AVOID_WARNING;
1093 SkDEBUGFAIL("unknown paint cap type");
1097 proc(devPath, *fRC, blitter);
1100 void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint,
1101 const SkMatrix* prePathMatrix, bool pathIsMutable,
1102 bool drawCoverage, SkBlitter* customBlitter) const {
1103 SkDEBUGCODE(this->validate();)
1106 if (fRC->isEmpty()) {
1110 SkPath* pathPtr = (SkPath*)&origSrcPath;
1114 const SkMatrix* matrix = fMatrix;
1115 tmpPath.setIsVolatile(true);
1117 if (prePathMatrix) {
1118 if (origPaint.getPathEffect() || origPaint.getStyle() != SkPaint::kFill_Style ||
1119 origPaint.getRasterizer()) {
1120 SkPath* result = pathPtr;
1122 if (!pathIsMutable) {
1124 pathIsMutable = true;
1126 pathPtr->transform(*prePathMatrix, result);
1129 tmpMatrix.setConcat(*matrix, *prePathMatrix);
1130 matrix = &tmpMatrix;
1133 // at this point we're done with prePathMatrix
1134 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
1136 SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
1140 if (SkDrawTreatAsHairline(origPaint, *matrix, &coverage)) {
1141 if (SK_Scalar1 == coverage) {
1142 paint.writable()->setStrokeWidth(0);
1143 } else if (SkBlendMode_SupportsCoverageAsAlpha(origPaint.getBlendMode())) {
1146 newAlpha = SkToU8(SkScalarRoundToInt(coverage *
1147 origPaint.getAlpha()));
1149 // this is the old technique, which we preserve for now so
1150 // we don't change previous results (testing)
1151 // the new way seems fine, its just (a tiny bit) different
1152 int scale = (int)SkScalarMul(coverage, 256);
1153 newAlpha = origPaint.getAlpha() * scale >> 8;
1155 SkPaint* writablePaint = paint.writable();
1156 writablePaint->setStrokeWidth(0);
1157 writablePaint->setAlpha(newAlpha);
1162 if (paint->getPathEffect() || paint->getStyle() != SkPaint::kFill_Style) {
1164 const SkRect* cullRectPtr = nullptr;
1165 if (this->computeConservativeLocalClipBounds(&cullRect)) {
1166 cullRectPtr = &cullRect;
1168 doFill = paint->getFillPath(*pathPtr, &tmpPath, cullRectPtr,
1169 ComputeResScaleForStroking(*fMatrix));
1173 if (paint->getRasterizer()) {
1175 if (paint->getRasterizer()->rasterize(*pathPtr, *matrix,
1176 &fRC->getBounds(), paint->getMaskFilter(), &mask,
1177 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
1178 this->drawDevMask(mask, *paint);
1179 SkMask::FreeImage(mask.fImage);
1184 // avoid possibly allocating a new path in transform if we can
1185 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
1187 // transform the path into device space
1188 pathPtr->transform(*matrix, devPathPtr);
1190 this->drawDevPath(*devPathPtr, *paint, drawCoverage, customBlitter, doFill);
1193 void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap, const SkPaint& paint) const {
1194 SkASSERT(bitmap.colorType() == kAlpha_8_SkColorType);
1196 if (SkTreatAsSprite(*fMatrix, bitmap.dimensions(), paint)) {
1197 int ix = SkScalarRoundToInt(fMatrix->getTranslateX());
1198 int iy = SkScalarRoundToInt(fMatrix->getTranslateY());
1200 SkAutoPixmapUnlock result;
1201 if (!bitmap.requestLock(&result)) {
1204 const SkPixmap& pmap = result.pixmap();
1206 mask.fBounds.set(ix, iy, ix + pmap.width(), iy + pmap.height());
1207 mask.fFormat = SkMask::kA8_Format;
1208 mask.fRowBytes = SkToU32(pmap.rowBytes());
1209 // fImage is typed as writable, but in this case it is used read-only
1210 mask.fImage = (uint8_t*)pmap.addr8(0, 0);
1212 this->drawDevMask(mask, paint);
1213 } else { // need to xform the bitmap first
1218 SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height()));
1219 fMatrix->mapRect(&r);
1220 r.round(&mask.fBounds);
1222 // set the mask's bounds to the transformed bitmap-bounds,
1223 // clipped to the actual device
1226 devBounds.set(0, 0, fDst.width(), fDst.height());
1227 // need intersect(l, t, r, b) on irect
1228 if (!mask.fBounds.intersect(devBounds)) {
1233 mask.fFormat = SkMask::kA8_Format;
1234 mask.fRowBytes = SkAlign4(mask.fBounds.width());
1235 size_t size = mask.computeImageSize();
1237 // the mask is too big to allocated, draw nothing
1241 // allocate (and clear) our temp buffer to hold the transformed bitmap
1242 SkAutoTMalloc<uint8_t> storage(size);
1243 mask.fImage = storage.get();
1244 memset(mask.fImage, 0, size);
1246 // now draw our bitmap(src) into mask(dst), transformed by the matrix
1249 device.installPixels(SkImageInfo::MakeA8(mask.fBounds.width(), mask.fBounds.height()),
1250 mask.fImage, mask.fRowBytes);
1253 // need the unclipped top/left for the translate
1254 c.translate(-SkIntToScalar(mask.fBounds.fLeft),
1255 -SkIntToScalar(mask.fBounds.fTop));
1258 // We can't call drawBitmap, or we'll infinitely recurse. Instead
1259 // we manually build a shader and draw that into our new mask
1261 tmpPaint.setFlags(paint.getFlags());
1262 tmpPaint.setFilterQuality(paint.getFilterQuality());
1263 SkAutoBitmapShaderInstall install(bitmap, tmpPaint);
1265 rr.set(0, 0, SkIntToScalar(bitmap.width()),
1266 SkIntToScalar(bitmap.height()));
1267 c.drawRect(rr, install.paintWithShader());
1269 this->drawDevMask(mask, paint);
1273 static bool clipped_out(const SkMatrix& m, const SkRasterClip& c,
1274 const SkRect& srcR) {
1276 m.mapRect(&dstR, srcR);
1277 return c.quickReject(dstR.roundOut());
1280 static bool clipped_out(const SkMatrix& matrix, const SkRasterClip& clip,
1281 int width, int height) {
1283 r.set(0, 0, SkIntToScalar(width), SkIntToScalar(height));
1284 return clipped_out(matrix, clip, r);
1287 static bool clipHandlesSprite(const SkRasterClip& clip, int x, int y, const SkPixmap& pmap) {
1288 return clip.isBW() || clip.quickContains(x, y, x + pmap.width(), y + pmap.height());
1291 void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix,
1292 const SkRect* dstBounds, const SkPaint& origPaint) const {
1293 SkDEBUGCODE(this->validate();)
1296 if (fRC->isEmpty() ||
1297 bitmap.width() == 0 || bitmap.height() == 0 ||
1298 bitmap.colorType() == kUnknown_SkColorType) {
1302 SkPaint paint(origPaint);
1303 paint.setStyle(SkPaint::kFill_Style);
1306 matrix.setConcat(*fMatrix, prematrix);
1308 if (clipped_out(matrix, *fRC, bitmap.width(), bitmap.height())) {
1312 if (bitmap.colorType() != kAlpha_8_SkColorType
1313 && SkTreatAsSprite(matrix, bitmap.dimensions(), paint)) {
1315 // It is safe to call lock pixels now, since we know the matrix is
1316 // (more or less) identity.
1318 SkAutoPixmapUnlock unlocker;
1319 if (!bitmap.requestLock(&unlocker)) {
1322 const SkPixmap& pmap = unlocker.pixmap();
1323 int ix = SkScalarRoundToInt(matrix.getTranslateX());
1324 int iy = SkScalarRoundToInt(matrix.getTranslateY());
1325 if (clipHandlesSprite(*fRC, ix, iy, pmap)) {
1326 SkTBlitterAllocator allocator;
1327 // blitter will be owned by the allocator.
1328 SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, paint, pmap, ix, iy, &allocator);
1330 SkScan::FillIRect(SkIRect::MakeXYWH(ix, iy, pmap.width(), pmap.height()),
1334 // if !blitter, then we fall-through to the slower case
1338 // now make a temp draw on the stack, and use it
1341 draw.fMatrix = &matrix;
1343 if (bitmap.colorType() == kAlpha_8_SkColorType) {
1344 draw.drawBitmapAsMask(bitmap, paint);
1346 SkAutoBitmapShaderInstall install(bitmap, paint);
1347 const SkPaint& paintWithShader = install.paintWithShader();
1348 const SkRect srcBounds = SkRect::MakeIWH(bitmap.width(), bitmap.height());
1350 this->drawRect(srcBounds, paintWithShader, &prematrix, dstBounds);
1352 draw.drawRect(srcBounds, paintWithShader);
1357 void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& origPaint) const {
1358 SkDEBUGCODE(this->validate();)
1361 if (fRC->isEmpty() ||
1362 bitmap.width() == 0 || bitmap.height() == 0 ||
1363 bitmap.colorType() == kUnknown_SkColorType) {
1367 const SkIRect bounds = SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height());
1369 if (fRC->quickReject(bounds)) {
1370 return; // nothing to draw
1373 SkPaint paint(origPaint);
1374 paint.setStyle(SkPaint::kFill_Style);
1376 SkAutoPixmapUnlock unlocker;
1377 if (!bitmap.requestLock(&unlocker)) {
1380 const SkPixmap& pmap = unlocker.pixmap();
1382 if (nullptr == paint.getColorFilter() && clipHandlesSprite(*fRC, x, y, pmap)) {
1383 SkTBlitterAllocator allocator;
1384 // blitter will be owned by the allocator.
1385 SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, paint, pmap, x, y, &allocator);
1387 SkScan::FillIRect(bounds, *fRC, blitter);
1395 // get a scalar version of our rect
1398 // create shader with offset
1399 matrix.setTranslate(r.fLeft, r.fTop);
1400 SkAutoBitmapShaderInstall install(bitmap, paint, &matrix);
1401 const SkPaint& shaderPaint = install.paintWithShader();
1405 draw.fMatrix = &matrix;
1406 // call ourself with a rect
1407 // is this OK if paint has a rasterizer?
1408 draw.drawRect(r, shaderPaint);
1411 ///////////////////////////////////////////////////////////////////////////////
1413 #include "SkScalerContext.h"
1414 #include "SkGlyphCache.h"
1415 #include "SkTextToPathIter.h"
1416 #include "SkUtils.h"
1418 bool SkDraw::ShouldDrawTextAsPaths(const SkPaint& paint, const SkMatrix& ctm) {
1419 // hairline glyphs are fast enough so we don't need to cache them
1420 if (SkPaint::kStroke_Style == paint.getStyle() && 0 == paint.getStrokeWidth()) {
1424 // we don't cache perspective
1425 if (ctm.hasPerspective()) {
1430 return SkPaint::TooBigToUseCache(ctm, *paint.setTextMatrix(&textM));
1433 void SkDraw::drawText_asPaths(const char text[], size_t byteLength,
1434 SkScalar x, SkScalar y,
1435 const SkPaint& paint) const {
1436 SkDEBUGCODE(this->validate();)
1438 SkTextToPathIter iter(text, byteLength, paint, true);
1441 matrix.setScale(iter.getPathScale(), iter.getPathScale());
1442 matrix.postTranslate(x, y);
1444 const SkPath* iterPath;
1445 SkScalar xpos, prevXPos = 0;
1447 while (iter.next(&iterPath, &xpos)) {
1448 matrix.postTranslate(xpos - prevXPos, 0);
1450 const SkPaint& pnt = iter.getPaint();
1452 fDevice->drawPath(*this, *iterPath, pnt, &matrix, false);
1454 this->drawPath(*iterPath, pnt, &matrix, false);
1461 // disable warning : local variable used without having been initialized
1463 #pragma warning ( push )
1464 #pragma warning ( disable : 4701 )
1467 ////////////////////////////////////////////////////////////////////////////////////////////////////
1469 class DrawOneGlyph {
1471 DrawOneGlyph(const SkDraw& draw, const SkPaint& paint, SkGlyphCache* cache, SkBlitter* blitter)
1472 : fUseRegionToDraw(UsingRegionToDraw(draw.fRC))
1473 , fGlyphCache(cache)
1475 , fClip(fUseRegionToDraw ? &draw.fRC->bwRgn() : nullptr)
1478 , fClipBounds(PickClipBounds(draw)) { }
1480 void operator()(const SkGlyph& glyph, SkPoint position, SkPoint rounding) {
1481 position += rounding;
1482 // Prevent glyphs from being drawn outside of or straddling the edge of device space.
1483 // Comparisons written a little weirdly so that NaN coordinates are treated safely.
1484 auto gt = [](float a, int b) { return !(a <= (float)b); };
1485 auto lt = [](float a, int b) { return !(a >= (float)b); };
1486 if (gt(position.fX, INT_MAX - (INT16_MAX + UINT16_MAX)) ||
1487 lt(position.fX, INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/)) ||
1488 gt(position.fY, INT_MAX - (INT16_MAX + UINT16_MAX)) ||
1489 lt(position.fY, INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/))) {
1493 int left = SkScalarFloorToInt(position.fX);
1494 int top = SkScalarFloorToInt(position.fY);
1495 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1497 left += glyph.fLeft;
1500 int right = left + glyph.fWidth;
1501 int bottom = top + glyph.fHeight;
1504 mask.fBounds.set(left, top, right, bottom);
1505 SkASSERT(!mask.fBounds.isEmpty());
1507 if (fUseRegionToDraw) {
1508 SkRegion::Cliperator clipper(*fClip, mask.fBounds);
1510 if (!clipper.done() && this->getImageData(glyph, &mask)) {
1511 const SkIRect& cr = clipper.rect();
1513 this->blitMask(mask, cr);
1515 } while (!clipper.done());
1519 SkIRect* bounds = &mask.fBounds;
1521 // this extra test is worth it, assuming that most of the time it succeeds
1522 // since we can avoid writing to storage
1523 if (!fClipBounds.containsNoEmptyCheck(mask.fBounds)) {
1524 if (!storage.intersectNoEmptyCheck(mask.fBounds, fClipBounds))
1529 if (this->getImageData(glyph, &mask)) {
1530 this->blitMask(mask, *bounds);
1536 static bool UsingRegionToDraw(const SkRasterClip* rClip) {
1537 return rClip->isBW() && !rClip->isRect();
1540 static SkIRect PickClipBounds(const SkDraw& draw) {
1541 const SkRasterClip& rasterClip = *draw.fRC;
1543 if (rasterClip.isBW()) {
1544 return rasterClip.bwRgn().getBounds();
1546 return rasterClip.aaRgn().getBounds();
1550 bool getImageData(const SkGlyph& glyph, SkMask* mask) {
1551 uint8_t* bits = (uint8_t*)(fGlyphCache->findImage(glyph));
1552 if (nullptr == bits) {
1553 return false; // can't rasterize glyph
1555 mask->fImage = bits;
1556 mask->fRowBytes = glyph.rowBytes();
1557 mask->fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
1561 void blitMask(const SkMask& mask, const SkIRect& clip) const {
1562 if (SkMask::kARGB32_Format == mask.fFormat) {
1565 SkImageInfo::MakeN32Premul(mask.fBounds.width(), mask.fBounds.height()),
1566 (SkPMColor*)mask.fImage, mask.fRowBytes);
1568 fDraw.drawSprite(bm, mask.fBounds.x(), mask.fBounds.y(), fPaint);
1570 fBlitter->blitMask(mask, clip);
1574 const bool fUseRegionToDraw;
1575 SkGlyphCache * const fGlyphCache;
1576 SkBlitter * const fBlitter;
1577 const SkRegion* const fClip;
1578 const SkDraw& fDraw;
1579 const SkPaint& fPaint;
1580 const SkIRect fClipBounds;
1583 ////////////////////////////////////////////////////////////////////////////////////////////////////
1585 uint32_t SkDraw::scalerContextFlags() const {
1586 uint32_t flags = SkPaint::kBoostContrast_ScalerContextFlag;
1587 if (!SkImageInfoIsGammaCorrect(fDevice->imageInfo())) {
1588 flags |= SkPaint::kFakeGamma_ScalerContextFlag;
1593 void SkDraw::drawText(const char text[], size_t byteLength,
1594 SkScalar x, SkScalar y, const SkPaint& paint) const {
1595 SkASSERT(byteLength == 0 || text != nullptr);
1597 SkDEBUGCODE(this->validate();)
1600 if (text == nullptr || byteLength == 0 || fRC->isEmpty()) {
1604 // SkScalarRec doesn't currently have a way of representing hairline stroke and
1605 // will fill if its frame-width is 0.
1606 if (ShouldDrawTextAsPaths(paint, *fMatrix)) {
1607 this->drawText_asPaths(text, byteLength, x, y, paint);
1611 SkAutoGlyphCache cache(paint, &fDevice->surfaceProps(), this->scalerContextFlags(), fMatrix);
1613 // The Blitter Choose needs to be live while using the blitter below.
1614 SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint);
1615 SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get());
1616 DrawOneGlyph drawOneGlyph(*this, paint, cache.get(), wrapper.getBlitter());
1618 SkFindAndPlaceGlyph::ProcessText(
1619 paint.getTextEncoding(), text, byteLength,
1620 {x, y}, *fMatrix, paint.getTextAlign(), cache.get(), drawOneGlyph);
1623 //////////////////////////////////////////////////////////////////////////////
1625 void SkDraw::drawPosText_asPaths(const char text[], size_t byteLength,
1626 const SkScalar pos[], int scalarsPerPosition,
1627 const SkPoint& offset, const SkPaint& origPaint) const {
1628 // setup our std paint, in hopes of getting hits in the cache
1629 SkPaint paint(origPaint);
1630 SkScalar matrixScale = paint.setupForAsPaths();
1633 matrix.setScale(matrixScale, matrixScale);
1635 // Temporarily jam in kFill, so we only ever ask for the raw outline from the cache.
1636 paint.setStyle(SkPaint::kFill_Style);
1637 paint.setPathEffect(nullptr);
1639 SkPaint::GlyphCacheProc glyphCacheProc = SkPaint::GetGlyphCacheProc(paint.getTextEncoding(),
1640 paint.isDevKernText(),
1642 SkAutoGlyphCache cache(paint, &fDevice->surfaceProps(), this->scalerContextFlags(), nullptr);
1644 const char* stop = text + byteLength;
1645 SkTextAlignProc alignProc(paint.getTextAlign());
1646 SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition);
1648 // Now restore the original settings, so we "draw" with whatever style/stroking.
1649 paint.setStyle(origPaint.getStyle());
1650 paint.setPathEffect(sk_ref_sp(origPaint.getPathEffect()));
1652 while (text < stop) {
1653 const SkGlyph& glyph = glyphCacheProc(cache.get(), &text);
1655 const SkPath* path = cache->findPath(glyph);
1658 tmsProc(pos, &tmsLoc);
1660 alignProc(tmsLoc, glyph, &loc);
1662 matrix[SkMatrix::kMTransX] = loc.fX;
1663 matrix[SkMatrix::kMTransY] = loc.fY;
1665 fDevice->drawPath(*this, *path, paint, &matrix, false);
1667 this->drawPath(*path, paint, &matrix, false);
1671 pos += scalarsPerPosition;
1675 void SkDraw::drawPosText(const char text[], size_t byteLength,
1676 const SkScalar pos[], int scalarsPerPosition,
1677 const SkPoint& offset, const SkPaint& paint) const {
1678 SkASSERT(byteLength == 0 || text != nullptr);
1679 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
1681 SkDEBUGCODE(this->validate();)
1684 if (text == nullptr || byteLength == 0 || fRC->isEmpty()) {
1688 if (ShouldDrawTextAsPaths(paint, *fMatrix)) {
1689 this->drawPosText_asPaths(text, byteLength, pos, scalarsPerPosition, offset, paint);
1693 SkAutoGlyphCache cache(paint, &fDevice->surfaceProps(), this->scalerContextFlags(), fMatrix);
1695 // The Blitter Choose needs to be live while using the blitter below.
1696 SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint);
1697 SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get());
1698 DrawOneGlyph drawOneGlyph(*this, paint, cache.get(), wrapper.getBlitter());
1699 SkPaint::Align textAlignment = paint.getTextAlign();
1701 SkFindAndPlaceGlyph::ProcessPosText(
1702 paint.getTextEncoding(), text, byteLength,
1703 offset, *fMatrix, pos, scalarsPerPosition, textAlignment, cache.get(), drawOneGlyph);
1707 #pragma warning ( pop )
1710 ///////////////////////////////////////////////////////////////////////////////
1712 static SkScan::HairRCProc ChooseHairProc(bool doAntiAlias) {
1713 return doAntiAlias ? SkScan::AntiHairLine : SkScan::HairLine;
1716 static bool texture_to_matrix(const VertState& state, const SkPoint verts[],
1717 const SkPoint texs[], SkMatrix* matrix) {
1718 SkPoint src[3], dst[3];
1720 src[0] = texs[state.f0];
1721 src[1] = texs[state.f1];
1722 src[2] = texs[state.f2];
1723 dst[0] = verts[state.f0];
1724 dst[1] = verts[state.f1];
1725 dst[2] = verts[state.f2];
1726 return matrix->setPolyToPoly(src, dst, 3);
1729 class SkTriColorShader : public SkShader {
1733 class TriColorShaderContext : public SkShader::Context {
1735 TriColorShaderContext(const SkTriColorShader& shader, const ContextRec&);
1736 virtual ~TriColorShaderContext();
1737 void shadeSpan(int x, int y, SkPMColor dstC[], int count) override;
1740 bool setup(const SkPoint pts[], const SkColor colors[], int, int, int);
1742 SkMatrix fDstToUnit;
1743 SkPMColor fColors[3];
1746 typedef SkShader::Context INHERITED;
1749 struct TriColorShaderData {
1751 const SkColor* colors;
1752 const VertState *state;
1755 SK_TO_STRING_OVERRIDE()
1757 // For serialization. This will never be called.
1758 Factory getFactory() const override { sk_throw(); return nullptr; }
1760 // Supply setup data to context from drawing setup
1761 void bindSetupData(TriColorShaderData* setupData) { fSetupData = setupData; }
1763 // Take the setup data from context when needed.
1764 TriColorShaderData* takeSetupData() {
1765 TriColorShaderData *data = fSetupData;
1771 size_t onContextSize(const ContextRec&) const override;
1772 Context* onCreateContext(const ContextRec& rec, void* storage) const override {
1773 return new (storage) TriColorShaderContext(*this, rec);
1777 TriColorShaderData *fSetupData;
1779 typedef SkShader INHERITED;
1782 bool SkTriColorShader::TriColorShaderContext::setup(const SkPoint pts[], const SkColor colors[],
1783 int index0, int index1, int index2) {
1785 fColors[0] = SkPreMultiplyColor(colors[index0]);
1786 fColors[1] = SkPreMultiplyColor(colors[index1]);
1787 fColors[2] = SkPreMultiplyColor(colors[index2]);
1791 m.set(0, pts[index1].fX - pts[index0].fX);
1792 m.set(1, pts[index2].fX - pts[index0].fX);
1793 m.set(2, pts[index0].fX);
1794 m.set(3, pts[index1].fY - pts[index0].fY);
1795 m.set(4, pts[index2].fY - pts[index0].fY);
1796 m.set(5, pts[index0].fY);
1797 if (!m.invert(&im)) {
1800 // We can't call getTotalInverse(), because we explicitly don't want to look at the localmatrix
1801 // as our interators are intrinsically tied to the vertices, and nothing else.
1803 if (!this->getCTM().invert(&ctmInv)) {
1806 // TODO replace INV(m) * INV(ctm) with INV(ctm * m)
1807 fDstToUnit.setConcat(im, ctmInv);
1811 #include "SkColorPriv.h"
1812 #include "SkComposeShader.h"
1814 static int ScalarTo256(SkScalar v) {
1815 return static_cast<int>(SkScalarPin(v, 0, 1) * 256 + 0.5);
1818 SkTriColorShader::SkTriColorShader()
1820 , fSetupData(NULL) {}
1822 SkTriColorShader::TriColorShaderContext::TriColorShaderContext(const SkTriColorShader& shader,
1823 const ContextRec& rec)
1824 : INHERITED(shader, rec)
1827 SkTriColorShader::TriColorShaderContext::~TriColorShaderContext() {}
1829 size_t SkTriColorShader::onContextSize(const ContextRec&) const {
1830 return sizeof(TriColorShaderContext);
1833 void SkTriColorShader::TriColorShaderContext::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
1834 SkTriColorShader* parent = static_cast<SkTriColorShader*>(const_cast<SkShader*>(&fShader));
1835 TriColorShaderData* set = parent->takeSetupData();
1837 fSetup = setup(set->pts, set->colors, set->state->f0, set->state->f1, set->state->f2);
1841 // Invalid matrices. Not checked before so no need to assert.
1845 const int alphaScale = Sk255To256(this->getPaintAlpha());
1849 for (int i = 0; i < count; i++) {
1850 fDstToUnit.mapXY(SkIntToScalar(x), SkIntToScalar(y), &src);
1853 int scale1 = ScalarTo256(src.fX);
1854 int scale2 = ScalarTo256(src.fY);
1855 int scale0 = 256 - scale1 - scale2;
1857 if (scale1 > scale2) {
1858 scale2 = 256 - scale1;
1860 scale1 = 256 - scale2;
1865 if (256 != alphaScale) {
1866 scale0 = SkAlphaMul(scale0, alphaScale);
1867 scale1 = SkAlphaMul(scale1, alphaScale);
1868 scale2 = SkAlphaMul(scale2, alphaScale);
1871 dstC[i] = SkAlphaMulQ(fColors[0], scale0) +
1872 SkAlphaMulQ(fColors[1], scale1) +
1873 SkAlphaMulQ(fColors[2], scale2);
1877 #ifndef SK_IGNORE_TO_STRING
1878 void SkTriColorShader::toString(SkString* str) const {
1879 str->append("SkTriColorShader: (");
1881 this->INHERITED::toString(str);
1887 void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count,
1888 const SkPoint vertices[], const SkPoint textures[],
1889 const SkColor colors[], SkXfermode* xmode,
1890 const uint16_t indices[], int indexCount,
1891 const SkPaint& paint) const {
1892 SkASSERT(0 == count || vertices);
1894 // abort early if there is nothing to draw
1895 if (count < 3 || (indices && indexCount < 3) || fRC->isEmpty()) {
1899 // transform out vertices into device coordinates
1900 SkAutoSTMalloc<16, SkPoint> storage(count);
1901 SkPoint* devVerts = storage.get();
1902 fMatrix->mapPoints(devVerts, vertices, count);
1905 We can draw the vertices in 1 of 4 ways:
1907 - solid color (no shader/texture[], no colors[])
1908 - just colors (no shader/texture[], has colors[])
1909 - just texture (has shader/texture[], no colors[])
1910 - colors * texture (has shader/texture[], has colors[])
1912 Thus for texture drawing, we need both texture[] and a shader.
1915 auto triShader = sk_make_sp<SkTriColorShader>();
1918 SkShader* shader = p.getShader();
1919 if (nullptr == shader) {
1920 // if we have no shader, we ignore the texture coordinates
1922 } else if (nullptr == textures) {
1923 // if we don't have texture coordinates, ignore the shader
1924 p.setShader(nullptr);
1928 // setup the custom shader (if needed)
1930 if (nullptr == textures) {
1931 // just colors (no texture)
1932 p.setShader(triShader);
1936 sk_sp<SkXfermode> xfer = xmode ? sk_ref_sp(xmode)
1937 : SkXfermode::Make(SkXfermode::kModulate_Mode);
1938 p.setShader(SkShader::MakeComposeShader(triShader, sk_ref_sp(shader), std::move(xfer)));
1942 SkAutoBlitterChoose blitter(fDst, *fMatrix, p);
1943 // Abort early if we failed to create a shader context.
1944 if (blitter->isNullBlitter()) {
1948 // setup our state and function pointer for iterating triangles
1949 VertState state(count, indices, indexCount);
1950 VertState::Proc vertProc = state.chooseProc(vmode);
1952 if (textures || colors) {
1953 SkTriColorShader::TriColorShaderData verticesSetup = { vertices, colors, &state };
1955 while (vertProc(&state)) {
1958 if (texture_to_matrix(state, vertices, textures, &tempM)) {
1959 SkShader::ContextRec rec(p, *fMatrix, &tempM,
1960 SkBlitter::PreferredShaderDest(fDst.info()));
1961 if (!blitter->resetShaderContext(rec)) {
1967 triShader->bindSetupData(&verticesSetup);
1971 devVerts[state.f0], devVerts[state.f1], devVerts[state.f2]
1973 SkScan::FillTriangle(tmp, *fRC, blitter.get());
1974 triShader->bindSetupData(NULL);
1977 // no colors[] and no texture, stroke hairlines with paint's color.
1978 SkScan::HairRCProc hairProc = ChooseHairProc(paint.isAntiAlias());
1979 const SkRasterClip& clip = *fRC;
1980 while (vertProc(&state)) {
1982 devVerts[state.f0], devVerts[state.f1], devVerts[state.f2], devVerts[state.f0]
1984 hairProc(array, 4, clip, blitter.get());
1989 ///////////////////////////////////////////////////////////////////////////////
1990 ///////////////////////////////////////////////////////////////////////////////
1994 void SkDraw::validate() const {
1995 SkASSERT(fMatrix != nullptr);
1996 SkASSERT(fRC != nullptr);
1998 const SkIRect& cr = fRC->getBounds();
2001 br.set(0, 0, fDst.width(), fDst.height());
2002 SkASSERT(cr.isEmpty() || br.contains(cr));
2007 ////////////////////////////////////////////////////////////////////////////////////////////////
2011 #include "SkRegion.h"
2012 #include "SkBlitter.h"
2014 static bool compute_bounds(const SkPath& devPath, const SkIRect* clipBounds,
2015 const SkMaskFilter* filter, const SkMatrix* filterMatrix,
2017 if (devPath.isEmpty()) {
2021 // init our bounds from the path
2022 *bounds = devPath.getBounds().makeOutset(SK_ScalarHalf, SK_ScalarHalf).roundOut();
2024 SkIPoint margin = SkIPoint::Make(0, 0);
2026 SkASSERT(filterMatrix);
2030 srcM.fBounds = *bounds;
2031 srcM.fFormat = SkMask::kA8_Format;
2032 if (!filter->filterMask(&dstM, srcM, *filterMatrix, &margin)) {
2037 // (possibly) trim the bounds to reflect the clip
2038 // (plus whatever slop the filter needs)
2040 // Ugh. Guard against gigantic margins from wacky filters. Without this
2041 // check we can request arbitrary amounts of slop beyond our visible
2042 // clip, and bring down the renderer (at least on finite RAM machines
2043 // like handsets, etc.). Need to balance this invented value between
2044 // quality of large filters like blurs, and the corresponding memory
2046 static const int MAX_MARGIN = 128;
2047 if (!bounds->intersect(clipBounds->makeOutset(SkMin32(margin.fX, MAX_MARGIN),
2048 SkMin32(margin.fY, MAX_MARGIN)))) {
2056 static void draw_into_mask(const SkMask& mask, const SkPath& devPath,
2057 SkStrokeRec::InitStyle style) {
2059 if (!draw.fDst.reset(mask)) {
2067 clip.setRect(SkIRect::MakeWH(mask.fBounds.width(), mask.fBounds.height()));
2068 matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
2069 -SkIntToScalar(mask.fBounds.fTop));
2072 draw.fMatrix = &matrix;
2073 paint.setAntiAlias(true);
2075 case SkStrokeRec::kHairline_InitStyle:
2076 SkASSERT(!paint.getStrokeWidth());
2077 paint.setStyle(SkPaint::kStroke_Style);
2079 case SkStrokeRec::kFill_InitStyle:
2080 SkASSERT(paint.getStyle() == SkPaint::kFill_Style);
2084 draw.drawPath(devPath, paint);
2087 bool SkDraw::DrawToMask(const SkPath& devPath, const SkIRect* clipBounds,
2088 const SkMaskFilter* filter, const SkMatrix* filterMatrix,
2089 SkMask* mask, SkMask::CreateMode mode,
2090 SkStrokeRec::InitStyle style) {
2091 if (SkMask::kJustRenderImage_CreateMode != mode) {
2092 if (!compute_bounds(devPath, clipBounds, filter, filterMatrix, &mask->fBounds))
2096 if (SkMask::kComputeBoundsAndRenderImage_CreateMode == mode) {
2097 mask->fFormat = SkMask::kA8_Format;
2098 mask->fRowBytes = mask->fBounds.width();
2099 size_t size = mask->computeImageSize();
2101 // we're too big to allocate the mask, abort
2104 mask->fImage = SkMask::AllocImage(size);
2105 memset(mask->fImage, 0, mask->computeImageSize());
2108 if (SkMask::kJustComputeBounds_CreateMode != mode) {
2109 draw_into_mask(*mask, devPath, style);