LCOV - app.info - gfx/skia/src/core/SkDraw.cpp

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-07-07 | 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