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