LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/core - SkDraw.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 385 1084 35.5 %
Date: 2017-07-14 16:53:18 Functions: 45 97 46.4 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13