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