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