LCOV - code coverage report
Current view: directory - gfx/skia/src/core - SkDraw.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1273 0 0.0 %
Date: 2012-06-02 Functions: 104 0 0.0 %

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

Generated by: LCOV version 1.7