LCOV - code coverage report
Current view: directory - gfx/skia/src/core - SkCanvas.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 902 1 0.1 %
Date: 2012-06-02 Functions: 132 2 1.5 %

       1                 : 
       2                 : /*
       3                 :  * Copyright 2008 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 "SkCanvas.h"
      11                 : #include "SkBounder.h"
      12                 : #include "SkDevice.h"
      13                 : #include "SkDraw.h"
      14                 : #include "SkDrawFilter.h"
      15                 : #include "SkDrawLooper.h"
      16                 : #include "SkPicture.h"
      17                 : #include "SkRasterClip.h"
      18                 : #include "SkScalarCompare.h"
      19                 : #include "SkTemplates.h"
      20                 : #include "SkTextFormatParams.h"
      21                 : #include "SkTLazy.h"
      22                 : #include "SkUtils.h"
      23                 : 
      24                 : //#define SK_TRACE_SAVERESTORE
      25                 : 
      26                 : #ifdef SK_TRACE_SAVERESTORE
      27                 :     static int gLayerCounter;
      28                 :     static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
      29                 :     static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
      30                 : 
      31                 :     static int gRecCounter;
      32                 :     static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
      33                 :     static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
      34                 : 
      35                 :     static int gCanvasCounter;
      36                 :     static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
      37                 :     static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
      38                 : #else
      39                 :     #define inc_layer()
      40                 :     #define dec_layer()
      41                 :     #define inc_rec()
      42                 :     #define dec_rec()
      43                 :     #define inc_canvas()
      44                 :     #define dec_canvas()
      45                 : #endif
      46                 : 
      47                 : typedef SkTLazy<SkPaint> SkLazyPaint;
      48                 : 
      49                 : ///////////////////////////////////////////////////////////////////////////////
      50                 : // Helpers for computing fast bounds for quickReject tests
      51                 : 
      52               0 : static SkCanvas::EdgeType paint2EdgeType(const SkPaint* paint) {
      53               0 :     return paint != NULL && paint->isAntiAlias() ?
      54               0 :             SkCanvas::kAA_EdgeType : SkCanvas::kBW_EdgeType;
      55                 : }
      56                 : 
      57                 : ///////////////////////////////////////////////////////////////////////////////
      58                 : 
      59                 : /*  This is the record we keep for each SkDevice that the user installs.
      60                 :     The clip/matrix/proc are fields that reflect the top of the save/restore
      61                 :     stack. Whenever the canvas changes, it marks a dirty flag, and then before
      62                 :     these are used (assuming we're not on a layer) we rebuild these cache
      63                 :     values: they reflect the top of the save stack, but translated and clipped
      64                 :     by the device's XY offset and bitmap-bounds.
      65                 : */
      66                 : struct DeviceCM {
      67                 :     DeviceCM*           fNext;
      68                 :     SkDevice*           fDevice;
      69                 :     SkRasterClip        fClip;
      70                 :     const SkMatrix*     fMatrix;
      71                 :     SkPaint*            fPaint; // may be null (in the future)
      72                 :     // optional, related to canvas' external matrix
      73                 :     const SkMatrix*     fMVMatrix;
      74                 :     const SkMatrix*     fExtMatrix;
      75                 : 
      76               0 :     DeviceCM(SkDevice* device, int x, int y, const SkPaint* paint)
      77               0 :             : fNext(NULL) {
      78               0 :         if (NULL != device) {
      79               0 :             device->ref();
      80               0 :             device->lockPixels();
      81                 :         }
      82               0 :         fDevice = device;
      83               0 :         fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL;
      84               0 :     }
      85                 : 
      86               0 :     ~DeviceCM() {
      87               0 :         if (NULL != fDevice) {
      88               0 :             fDevice->unlockPixels();
      89               0 :             fDevice->unref();
      90                 :         }
      91               0 :         SkDELETE(fPaint);
      92               0 :     }
      93                 : 
      94               0 :     void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
      95                 :                   const SkClipStack& clipStack, SkRasterClip* updateClip) {
      96               0 :         int x = fDevice->getOrigin().x();
      97               0 :         int y = fDevice->getOrigin().y();
      98               0 :         int width = fDevice->width();
      99               0 :         int height = fDevice->height();
     100                 : 
     101               0 :         if ((x | y) == 0) {
     102               0 :             fMatrix = &totalMatrix;
     103               0 :             fClip = totalClip;
     104                 :         } else {
     105               0 :             fMatrixStorage = totalMatrix;
     106                 :             fMatrixStorage.postTranslate(SkIntToScalar(-x),
     107               0 :                                          SkIntToScalar(-y));
     108               0 :             fMatrix = &fMatrixStorage;
     109                 : 
     110               0 :             totalClip.translate(-x, -y, &fClip);
     111                 :         }
     112                 : 
     113               0 :         fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
     114                 : 
     115                 :         // intersect clip, but don't translate it (yet)
     116                 : 
     117               0 :         if (updateClip) {
     118                 :             updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
     119               0 :                            SkRegion::kDifference_Op);
     120                 :         }
     121                 : 
     122               0 :         fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
     123                 : 
     124                 : #ifdef SK_DEBUG
     125               0 :         if (!fClip.isEmpty()) {
     126                 :             SkIRect deviceR;
     127               0 :             deviceR.set(0, 0, width, height);
     128               0 :             SkASSERT(deviceR.contains(fClip.getBounds()));
     129                 :         }
     130                 : #endif
     131                 :         // default is to assume no external matrix
     132               0 :         fMVMatrix = NULL;
     133               0 :         fExtMatrix = NULL;
     134               0 :     }
     135                 : 
     136                 :     // can only be called after calling updateMC()
     137               0 :     void updateExternalMatrix(const SkMatrix& extM, const SkMatrix& extI) {
     138               0 :         fMVMatrixStorage.setConcat(extI, *fMatrix);
     139               0 :         fMVMatrix = &fMVMatrixStorage;
     140               0 :         fExtMatrix = &extM; // assumes extM has long life-time (owned by canvas)
     141               0 :     }
     142                 : 
     143                 : private:
     144                 :     SkMatrix    fMatrixStorage, fMVMatrixStorage;
     145                 : };
     146                 : 
     147                 : /*  This is the record we keep for each save/restore level in the stack.
     148                 :     Since a level optionally copies the matrix and/or stack, we have pointers
     149                 :     for these fields. If the value is copied for this level, the copy is
     150                 :     stored in the ...Storage field, and the pointer points to that. If the
     151                 :     value is not copied for this level, we ignore ...Storage, and just point
     152                 :     at the corresponding value in the previous level in the stack.
     153                 : */
     154                 : class SkCanvas::MCRec {
     155                 : public:
     156                 :     MCRec*          fNext;
     157                 :     SkMatrix*       fMatrix;        // points to either fMatrixStorage or prev MCRec
     158                 :     SkRasterClip*   fRasterClip;    // points to either fRegionStorage or prev MCRec
     159                 :     SkDrawFilter*   fFilter;        // the current filter (or null)
     160                 : 
     161                 :     DeviceCM*   fLayer;
     162                 :     /*  If there are any layers in the stack, this points to the top-most
     163                 :         one that is at or below this level in the stack (so we know what
     164                 :         bitmap/device to draw into from this level. This value is NOT
     165                 :         reference counted, since the real owner is either our fLayer field,
     166                 :         or a previous one in a lower level.)
     167                 :     */
     168                 :     DeviceCM*   fTopLayer;
     169                 : 
     170               0 :     MCRec(const MCRec* prev, int flags) {
     171               0 :         if (NULL != prev) {
     172               0 :             if (flags & SkCanvas::kMatrix_SaveFlag) {
     173               0 :                 fMatrixStorage = *prev->fMatrix;
     174               0 :                 fMatrix = &fMatrixStorage;
     175                 :             } else {
     176               0 :                 fMatrix = prev->fMatrix;
     177                 :             }
     178                 : 
     179               0 :             if (flags & SkCanvas::kClip_SaveFlag) {
     180               0 :                 fRasterClipStorage = *prev->fRasterClip;
     181               0 :                 fRasterClip = &fRasterClipStorage;
     182                 :             } else {
     183               0 :                 fRasterClip = prev->fRasterClip;
     184                 :             }
     185                 : 
     186               0 :             fFilter = prev->fFilter;
     187               0 :             SkSafeRef(fFilter);
     188                 : 
     189               0 :             fTopLayer = prev->fTopLayer;
     190                 :         } else {   // no prev
     191               0 :             fMatrixStorage.reset();
     192                 : 
     193               0 :             fMatrix     = &fMatrixStorage;
     194               0 :             fRasterClip = &fRasterClipStorage;
     195               0 :             fFilter     = NULL;
     196               0 :             fTopLayer   = NULL;
     197                 :         }
     198               0 :         fLayer = NULL;
     199                 : 
     200                 :         // don't bother initializing fNext
     201                 :         inc_rec();
     202               0 :     }
     203               0 :     ~MCRec() {
     204               0 :         SkSafeUnref(fFilter);
     205               0 :         SkDELETE(fLayer);
     206                 :         dec_rec();
     207               0 :     }
     208                 : 
     209                 : private:
     210                 :     SkMatrix        fMatrixStorage;
     211                 :     SkRasterClip    fRasterClipStorage;
     212                 : };
     213                 : 
     214               0 : class SkDrawIter : public SkDraw {
     215                 : public:
     216               0 :     SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
     217               0 :         fCanvas = canvas;
     218               0 :         canvas->updateDeviceCMCache();
     219                 : 
     220               0 :         fClipStack = &canvas->getTotalClipStack();
     221               0 :         fBounder = canvas->getBounder();
     222               0 :         fCurrLayer = canvas->fMCRec->fTopLayer;
     223               0 :         fSkipEmptyClips = skipEmptyClips;
     224               0 :     }
     225                 : 
     226               0 :     bool next() {
     227                 :         // skip over recs with empty clips
     228               0 :         if (fSkipEmptyClips) {
     229               0 :             while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
     230               0 :                 fCurrLayer = fCurrLayer->fNext;
     231                 :             }
     232                 :         }
     233                 : 
     234               0 :         if (NULL != fCurrLayer) {
     235               0 :             const DeviceCM* rec = fCurrLayer;
     236                 : 
     237               0 :             fMatrix = rec->fMatrix;
     238               0 :             fClip   = &((SkRasterClip*)&rec->fClip)->forceGetBW();
     239               0 :             fRC     = &rec->fClip;
     240               0 :             fDevice = rec->fDevice;
     241               0 :             fBitmap = &fDevice->accessBitmap(true);
     242               0 :             fPaint  = rec->fPaint;
     243               0 :             fMVMatrix = rec->fMVMatrix;
     244               0 :             fExtMatrix = rec->fExtMatrix;
     245               0 :             SkDEBUGCODE(this->validate();)
     246                 : 
     247               0 :             fCurrLayer = rec->fNext;
     248               0 :             if (fBounder) {
     249               0 :                 fBounder->setClip(fClip);
     250                 :             }
     251                 :             // fCurrLayer may be NULL now
     252                 : 
     253               0 :             fCanvas->prepareForDeviceDraw(fDevice, *fMatrix, *fClip, *fClipStack);
     254               0 :             return true;
     255                 :         }
     256               0 :         return false;
     257                 :     }
     258                 : 
     259               0 :     SkDevice* getDevice() const { return fDevice; }
     260               0 :     int getX() const { return fDevice->getOrigin().x(); }
     261               0 :     int getY() const { return fDevice->getOrigin().y(); }
     262               0 :     const SkMatrix& getMatrix() const { return *fMatrix; }
     263               0 :     const SkRegion& getClip() const { return *fClip; }
     264               0 :     const SkPaint* getPaint() const { return fPaint; }
     265                 : 
     266                 : private:
     267                 :     SkCanvas*       fCanvas;
     268                 :     const DeviceCM* fCurrLayer;
     269                 :     const SkPaint*  fPaint;     // May be null.
     270                 :     SkBool8         fSkipEmptyClips;
     271                 : 
     272                 :     typedef SkDraw INHERITED;
     273                 : };
     274                 : 
     275                 : /////////////////////////////////////////////////////////////////////////////
     276                 : 
     277                 : class AutoDrawLooper {
     278                 : public:
     279               0 :     AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint) : fOrigPaint(paint) {
     280               0 :         fCanvas = canvas;
     281               0 :         fLooper = paint.getLooper();
     282               0 :         fFilter = canvas->getDrawFilter();
     283               0 :         fPaint = NULL;
     284               0 :         fSaveCount = canvas->getSaveCount();
     285               0 :         fDone = false;
     286                 : 
     287               0 :         if (fLooper) {
     288               0 :             fLooper->init(canvas);
     289                 :         }
     290               0 :     }
     291                 :     
     292               0 :     ~AutoDrawLooper() {
     293               0 :         SkASSERT(fCanvas->getSaveCount() == fSaveCount);
     294               0 :     }
     295                 :     
     296               0 :     const SkPaint& paint() const {
     297               0 :         SkASSERT(fPaint);
     298               0 :         return *fPaint;
     299                 :     }
     300                 :     
     301                 :     bool next(SkDrawFilter::Type drawType);
     302                 :     
     303                 : private:
     304                 :     SkLazyPaint     fLazyPaint;
     305                 :     SkCanvas*       fCanvas;
     306                 :     const SkPaint&  fOrigPaint;
     307                 :     SkDrawLooper*   fLooper;
     308                 :     SkDrawFilter*   fFilter;
     309                 :     const SkPaint*  fPaint;
     310                 :     int             fSaveCount;
     311                 :     bool            fDone;
     312                 : };
     313                 : 
     314               0 : bool AutoDrawLooper::next(SkDrawFilter::Type drawType) {
     315               0 :     fPaint = NULL;
     316               0 :     if (fDone) {
     317               0 :         return false;
     318                 :     }
     319                 : 
     320               0 :     if (fLooper || fFilter) {
     321               0 :         SkPaint* paint = fLazyPaint.set(fOrigPaint);
     322               0 :         if (fLooper && !fLooper->next(fCanvas, paint)) {
     323               0 :             fDone = true;
     324               0 :             return false;
     325                 :         }
     326               0 :         if (fFilter) {
     327               0 :             fFilter->filter(paint, drawType);
     328               0 :             if (NULL == fLooper) {
     329                 :                 // no looper means we only draw once
     330               0 :                 fDone = true;
     331                 :             }
     332                 :         }
     333               0 :         fPaint = paint;
     334                 :     } else {
     335               0 :         fDone = true;
     336               0 :         fPaint = &fOrigPaint;
     337                 :     }
     338                 : 
     339                 :     // call this after any possible paint modifiers
     340               0 :     if (fPaint->nothingToDraw()) {
     341               0 :         fPaint = NULL;
     342               0 :         return false;
     343                 :     }
     344               0 :     return true;
     345                 : }
     346                 : 
     347                 : /*  Stack helper for managing a SkBounder. In the destructor, if we were
     348                 :     given a bounder, we call its commit() method, signifying that we are
     349                 :     done accumulating bounds for that draw.
     350                 : */
     351                 : class SkAutoBounderCommit {
     352                 : public:
     353               0 :     SkAutoBounderCommit(SkBounder* bounder) : fBounder(bounder) {}
     354               0 :     ~SkAutoBounderCommit() {
     355               0 :         if (NULL != fBounder) {
     356               0 :             fBounder->commit();
     357                 :         }
     358               0 :     }
     359                 : private:
     360                 :     SkBounder*  fBounder;
     361                 : };
     362                 : 
     363                 : #include "SkColorPriv.h"
     364                 : 
     365                 : class AutoValidator {
     366                 : public:
     367                 :     AutoValidator(SkDevice* device) : fDevice(device) {}
     368                 :     ~AutoValidator() {
     369                 : #ifdef SK_DEBUG
     370                 :         const SkBitmap& bm = fDevice->accessBitmap(false);
     371                 :         if (bm.config() == SkBitmap::kARGB_4444_Config) {
     372                 :             for (int y = 0; y < bm.height(); y++) {
     373                 :                 const SkPMColor16* p = bm.getAddr16(0, y);
     374                 :                 for (int x = 0; x < bm.width(); x++) {
     375                 :                     SkPMColor16 c = p[x];
     376                 :                     SkPMColor16Assert(c);
     377                 :                 }
     378                 :             }
     379                 :         }
     380                 : #endif
     381                 :     }
     382                 : private:
     383                 :     SkDevice* fDevice;
     384                 : };
     385                 : 
     386                 : ////////// macros to place around the internal draw calls //////////////////
     387                 : 
     388                 : #define LOOPER_BEGIN(paint, type)                                   \
     389                 : /*    AutoValidator   validator(fMCRec->fTopLayer->fDevice); */     \
     390                 :     AutoDrawLooper  looper(this, paint);                            \
     391                 :     while (looper.next(type)) {                                     \
     392                 :         SkAutoBounderCommit ac(fBounder);                           \
     393                 :         SkDrawIter          iter(this);
     394                 : 
     395                 : #define LOOPER_END    }
     396                 : 
     397                 : ////////////////////////////////////////////////////////////////////////////
     398                 : 
     399               0 : SkDevice* SkCanvas::init(SkDevice* device) {
     400               0 :     fBounder = NULL;
     401               0 :     fLocalBoundsCompareType.setEmpty();
     402               0 :     fLocalBoundsCompareTypeDirty = true;
     403               0 :     fLocalBoundsCompareTypeBW.setEmpty();
     404               0 :     fLocalBoundsCompareTypeDirtyBW = true;
     405               0 :     fLastDeviceToGainFocus = NULL;
     406               0 :     fDeviceCMDirty = false;
     407               0 :     fLayerCount = 0;
     408                 : 
     409               0 :     fMCRec = (MCRec*)fMCStack.push_back();
     410               0 :     new (fMCRec) MCRec(NULL, 0);
     411                 : 
     412               0 :     fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL));
     413               0 :     fMCRec->fTopLayer = fMCRec->fLayer;
     414               0 :     fMCRec->fNext = NULL;
     415                 : 
     416               0 :     fExternalMatrix.reset();
     417               0 :     fExternalInverse.reset();
     418               0 :     fUseExternalMatrix = false;
     419                 : 
     420               0 :     return this->setDevice(device);
     421                 : }
     422                 : 
     423               0 : SkCanvas::SkCanvas()
     424               0 : : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
     425                 :     inc_canvas();
     426                 :     
     427               0 :     this->init(NULL);
     428               0 : }
     429                 : 
     430               0 : SkCanvas::SkCanvas(SkDevice* device)
     431               0 :         : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
     432                 :     inc_canvas();
     433                 : 
     434               0 :     this->init(device);
     435               0 : }
     436                 : 
     437               0 : SkCanvas::SkCanvas(const SkBitmap& bitmap)
     438               0 :         : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
     439                 :     inc_canvas();
     440                 : 
     441               0 :     this->init(SkNEW_ARGS(SkDevice, (bitmap)))->unref();
     442               0 : }
     443                 : 
     444               0 : SkCanvas::~SkCanvas() {
     445                 :     // free up the contents of our deque
     446               0 :     this->restoreToCount(1);    // restore everything but the last
     447               0 :     SkASSERT(0 == fLayerCount);
     448                 : 
     449               0 :     this->internalRestore();    // restore the last, since we're going away
     450                 : 
     451               0 :     SkSafeUnref(fBounder);
     452                 : 
     453                 :     dec_canvas();
     454               0 : }
     455                 : 
     456               0 : SkBounder* SkCanvas::setBounder(SkBounder* bounder) {
     457               0 :     SkRefCnt_SafeAssign(fBounder, bounder);
     458               0 :     return bounder;
     459                 : }
     460                 : 
     461               0 : SkDrawFilter* SkCanvas::getDrawFilter() const {
     462               0 :     return fMCRec->fFilter;
     463                 : }
     464                 : 
     465               0 : SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
     466               0 :     SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
     467               0 :     return filter;
     468                 : }
     469                 : 
     470                 : ///////////////////////////////////////////////////////////////////////////////
     471                 : 
     472               0 : SkISize SkCanvas::getDeviceSize() const {
     473               0 :     SkDevice* d = this->getDevice();
     474               0 :     return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
     475                 : }
     476                 : 
     477               0 : SkDevice* SkCanvas::getDevice() const {
     478                 :     // return root device
     479               0 :     SkDeque::F2BIter iter(fMCStack);
     480               0 :     MCRec*           rec = (MCRec*)iter.next();
     481               0 :     SkASSERT(rec && rec->fLayer);
     482               0 :     return rec->fLayer->fDevice;
     483                 : }
     484                 : 
     485               0 : SkDevice* SkCanvas::getTopDevice() const {
     486               0 :     return fMCRec->fTopLayer->fDevice;
     487                 : }
     488                 : 
     489               0 : SkDevice* SkCanvas::setDevice(SkDevice* device) {
     490                 :     // return root device
     491               0 :     SkDeque::F2BIter iter(fMCStack);
     492               0 :     MCRec*           rec = (MCRec*)iter.next();
     493               0 :     SkASSERT(rec && rec->fLayer);
     494               0 :     SkDevice*       rootDevice = rec->fLayer->fDevice;
     495                 : 
     496               0 :     if (rootDevice == device) {
     497               0 :         return device;
     498                 :     }
     499                 : 
     500                 :     /* Notify the devices that they are going in/out of scope, so they can do
     501                 :        things like lock/unlock their pixels, etc.
     502                 :     */
     503               0 :     if (device) {
     504               0 :         device->lockPixels();
     505                 :     }
     506               0 :     if (rootDevice) {
     507               0 :         rootDevice->unlockPixels();
     508                 :     }
     509                 : 
     510               0 :     SkRefCnt_SafeAssign(rec->fLayer->fDevice, device);
     511               0 :     rootDevice = device;
     512                 : 
     513               0 :     fDeviceCMDirty = true;
     514                 : 
     515                 :     /*  Now we update our initial region to have the bounds of the new device,
     516                 :         and then intersect all of the clips in our stack with these bounds,
     517                 :         to ensure that we can't draw outside of the device's bounds (and trash
     518                 :                                                                      memory).
     519                 : 
     520                 :     NOTE: this is only a partial-fix, since if the new device is larger than
     521                 :         the previous one, we don't know how to "enlarge" the clips in our stack,
     522                 :         so drawing may be artificially restricted. Without keeping a history of
     523                 :         all calls to canvas->clipRect() and canvas->clipPath(), we can't exactly
     524                 :         reconstruct the correct clips, so this approximation will have to do.
     525                 :         The caller really needs to restore() back to the base if they want to
     526                 :         accurately take advantage of the new device bounds.
     527                 :     */
     528                 : 
     529               0 :     if (NULL == device) {
     530               0 :         rec->fRasterClip->setEmpty();
     531               0 :         while ((rec = (MCRec*)iter.next()) != NULL) {
     532               0 :             (void)rec->fRasterClip->setEmpty();
     533                 :         }
     534               0 :         fClipStack.reset();
     535                 :     } else {
     536                 :         // compute our total bounds for all devices
     537                 :         SkIRect bounds;
     538                 : 
     539               0 :         bounds.set(0, 0, device->width(), device->height());
     540                 : 
     541                 :         // now jam our 1st clip to be bounds, and intersect the rest with that
     542               0 :         rec->fRasterClip->setRect(bounds);
     543               0 :         while ((rec = (MCRec*)iter.next()) != NULL) {
     544               0 :             (void)rec->fRasterClip->op(bounds, SkRegion::kIntersect_Op);
     545                 :         }
     546                 :     }
     547               0 :     return device;
     548                 : }
     549                 : 
     550               0 : SkDevice* SkCanvas::setBitmapDevice(const SkBitmap& bitmap) {
     551               0 :     SkDevice* device = this->setDevice(SkNEW_ARGS(SkDevice, (bitmap)));
     552               0 :     device->unref();
     553               0 :     return device;
     554                 : }
     555                 : 
     556               0 : bool SkCanvas::readPixels(SkBitmap* bitmap,
     557                 :                           int x, int y,
     558                 :                           Config8888 config8888) {
     559               0 :     SkDevice* device = this->getDevice();
     560               0 :     if (!device) {
     561               0 :         return false;
     562                 :     }
     563               0 :     return device->readPixels(bitmap, x, y, config8888);
     564                 : }
     565                 : 
     566               0 : bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
     567               0 :     SkDevice* device = this->getDevice();
     568                 :     
     569                 :     SkIRect bounds;
     570               0 :     bounds.set(0, 0, device->width(), device->height());
     571               0 :     if (!bounds.intersect(srcRect)) {
     572               0 :         return false;
     573                 :     }
     574                 : 
     575               0 :     SkBitmap tmp;
     576                 :     tmp.setConfig(SkBitmap::kARGB_8888_Config, bounds.width(),
     577               0 :                                                bounds.height());
     578               0 :     if (this->readPixels(&tmp, bounds.fLeft, bounds.fTop)) {
     579               0 :         bitmap->swap(tmp);
     580               0 :         return true;
     581                 :     } else {
     582               0 :         return false;
     583                 :     }
     584                 : }
     585                 : 
     586               0 : void SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y,
     587                 :                            Config8888 config8888) {
     588               0 :     SkDevice* device = this->getDevice();
     589               0 :     if (device) {
     590               0 :         device->writePixels(bitmap, x, y, config8888);
     591                 :     }
     592               0 : }
     593                 : 
     594                 : //////////////////////////////////////////////////////////////////////////////
     595                 : 
     596               0 : void SkCanvas::updateDeviceCMCache() {
     597               0 :     if (fDeviceCMDirty) {
     598               0 :         const SkMatrix& totalMatrix = this->getTotalMatrix();
     599               0 :         const SkRasterClip& totalClip = *fMCRec->fRasterClip;
     600               0 :         DeviceCM*       layer = fMCRec->fTopLayer;
     601                 : 
     602               0 :         if (NULL == layer->fNext) {   // only one layer
     603               0 :             layer->updateMC(totalMatrix, totalClip, fClipStack, NULL);
     604               0 :             if (fUseExternalMatrix) {
     605                 :                 layer->updateExternalMatrix(fExternalMatrix,
     606               0 :                                             fExternalInverse);
     607                 :             }
     608                 :         } else {
     609               0 :             SkRasterClip clip(totalClip);
     610               0 :             do {
     611               0 :                 layer->updateMC(totalMatrix, clip, fClipStack, &clip);
     612               0 :                 if (fUseExternalMatrix) {
     613                 :                     layer->updateExternalMatrix(fExternalMatrix,
     614               0 :                                                 fExternalInverse);
     615                 :                 }
     616                 :             } while ((layer = layer->fNext) != NULL);
     617                 :         }
     618               0 :         fDeviceCMDirty = false;
     619                 :     }
     620               0 : }
     621                 : 
     622               0 : void SkCanvas::prepareForDeviceDraw(SkDevice* device, const SkMatrix& matrix,
     623                 :                                     const SkRegion& clip,
     624                 :                                     const SkClipStack& clipStack) {
     625               0 :     SkASSERT(device);
     626               0 :     if (fLastDeviceToGainFocus != device) {
     627               0 :         device->gainFocus(this, matrix, clip, clipStack);
     628               0 :         fLastDeviceToGainFocus = device;
     629                 :     }
     630               0 : }
     631                 : 
     632                 : ///////////////////////////////////////////////////////////////////////////////
     633                 : 
     634               0 : int SkCanvas::internalSave(SaveFlags flags) {
     635               0 :     int saveCount = this->getSaveCount(); // record this before the actual save
     636                 : 
     637               0 :     MCRec* newTop = (MCRec*)fMCStack.push_back();
     638               0 :     new (newTop) MCRec(fMCRec, flags);    // balanced in restore()
     639                 : 
     640               0 :     newTop->fNext = fMCRec;
     641               0 :     fMCRec = newTop;
     642                 : 
     643               0 :     fClipStack.save();
     644               0 :     SkASSERT(fClipStack.getSaveCount() == this->getSaveCount() - 1);
     645                 : 
     646               0 :     return saveCount;
     647                 : }
     648                 : 
     649               0 : int SkCanvas::save(SaveFlags flags) {
     650                 :     // call shared impl
     651               0 :     return this->internalSave(flags);
     652                 : }
     653                 : 
     654                 : #define C32MASK (1 << SkBitmap::kARGB_8888_Config)
     655                 : #define C16MASK (1 << SkBitmap::kRGB_565_Config)
     656                 : #define C8MASK  (1 << SkBitmap::kA8_Config)
     657                 : 
     658               0 : static SkBitmap::Config resolve_config(SkCanvas* canvas,
     659                 :                                        const SkIRect& bounds,
     660                 :                                        SkCanvas::SaveFlags flags,
     661                 :                                        bool* isOpaque) {
     662               0 :     *isOpaque = (flags & SkCanvas::kHasAlphaLayer_SaveFlag) == 0;
     663                 : 
     664                 : #if 0
     665                 :     // loop through and union all the configs we may draw into
     666                 :     uint32_t configMask = 0;
     667                 :     for (int i = canvas->countLayerDevices() - 1; i >= 0; --i)
     668                 :     {
     669                 :         SkDevice* device = canvas->getLayerDevice(i);
     670                 :         if (device->intersects(bounds))
     671                 :             configMask |= 1 << device->config();
     672                 :     }
     673                 : 
     674                 :     // if the caller wants alpha or fullcolor, we can't return 565
     675                 :     if (flags & (SkCanvas::kFullColorLayer_SaveFlag |
     676                 :                  SkCanvas::kHasAlphaLayer_SaveFlag))
     677                 :         configMask &= ~C16MASK;
     678                 : 
     679                 :     switch (configMask) {
     680                 :     case C8MASK:    // if we only have A8, return that
     681                 :         return SkBitmap::kA8_Config;
     682                 : 
     683                 :     case C16MASK:   // if we only have 565, return that
     684                 :         return SkBitmap::kRGB_565_Config;
     685                 : 
     686                 :     default:
     687                 :         return SkBitmap::kARGB_8888_Config; // default answer
     688                 :     }
     689                 : #else
     690               0 :     return SkBitmap::kARGB_8888_Config; // default answer
     691                 : #endif
     692                 : }
     693                 : 
     694               0 : static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
     695               0 :     return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
     696                 : }
     697                 : 
     698               0 : int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
     699                 :                         SaveFlags flags) {
     700                 :     // do this before we create the layer. We don't call the public save() since
     701                 :     // that would invoke a possibly overridden virtual
     702               0 :     int count = this->internalSave(flags);
     703                 : 
     704               0 :     fDeviceCMDirty = true;
     705                 : 
     706                 :     SkIRect clipBounds;
     707               0 :     if (!this->getClipDeviceBounds(&clipBounds)) {
     708               0 :         return count;
     709                 :     }
     710                 : 
     711                 :     SkIRect ir;
     712               0 :     if (NULL != bounds) {
     713                 :         SkRect r;
     714                 : 
     715               0 :         this->getTotalMatrix().mapRect(&r, *bounds);
     716               0 :         r.roundOut(&ir);
     717                 :         // early exit if the layer's bounds are clipped out
     718               0 :         if (!ir.intersect(clipBounds)) {
     719               0 :             if (bounds_affects_clip(flags)) {
     720               0 :                 fMCRec->fRasterClip->setEmpty();
     721                 :             }
     722               0 :             return count;
     723                 :         }
     724                 :     } else {    // no user bounds, so just use the clip
     725               0 :         ir = clipBounds;
     726                 :     }
     727                 : 
     728               0 :     fClipStack.clipDevRect(ir, SkRegion::kIntersect_Op);
     729                 :     // early exit if the clip is now empty
     730               0 :     if (bounds_affects_clip(flags) &&
     731               0 :         !fMCRec->fRasterClip->op(ir, SkRegion::kIntersect_Op)) {
     732               0 :         return count;
     733                 :     }
     734                 : 
     735                 :     bool isOpaque;
     736               0 :     SkBitmap::Config config = resolve_config(this, ir, flags, &isOpaque);
     737                 : 
     738                 :     SkDevice* device;
     739               0 :     if (paint && paint->getImageFilter()) {
     740                 :         device = this->createCompatibleDevice(config, ir.width(), ir.height(),
     741               0 :                                               isOpaque);
     742                 :     } else {
     743                 :         device = this->createLayerDevice(config, ir.width(), ir.height(),
     744               0 :                                          isOpaque);
     745                 :     }
     746               0 :     if (NULL == device) {
     747               0 :         SkDebugf("Unable to create device for layer.");
     748               0 :         return count;
     749                 :     }
     750                 : 
     751               0 :     device->setOrigin(ir.fLeft, ir.fTop);
     752               0 :     DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint));
     753               0 :     device->unref();
     754                 : 
     755               0 :     layer->fNext = fMCRec->fTopLayer;
     756               0 :     fMCRec->fLayer = layer;
     757               0 :     fMCRec->fTopLayer = layer;    // this field is NOT an owner of layer
     758                 : 
     759               0 :     fLayerCount += 1;
     760               0 :     return count;
     761                 : }
     762                 : 
     763               0 : int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
     764                 :                              SaveFlags flags) {
     765               0 :     if (0xFF == alpha) {
     766               0 :         return this->saveLayer(bounds, NULL, flags);
     767                 :     } else {
     768               0 :         SkPaint tmpPaint;
     769               0 :         tmpPaint.setAlpha(alpha);
     770               0 :         return this->saveLayer(bounds, &tmpPaint, flags);
     771                 :     }
     772                 : }
     773                 : 
     774               0 : void SkCanvas::restore() {
     775                 :     // check for underflow
     776               0 :     if (fMCStack.count() > 1) {
     777               0 :         this->internalRestore();
     778                 :     }
     779               0 : }
     780                 : 
     781               0 : void SkCanvas::internalRestore() {
     782               0 :     SkASSERT(fMCStack.count() != 0);
     783                 : 
     784               0 :     fDeviceCMDirty = true;
     785               0 :     fLocalBoundsCompareTypeDirty = true;
     786               0 :     fLocalBoundsCompareTypeDirtyBW = true;
     787                 : 
     788               0 :     fClipStack.restore();
     789                 :     // reserve our layer (if any)
     790               0 :     DeviceCM* layer = fMCRec->fLayer;   // may be null
     791                 :     // now detach it from fMCRec so we can pop(). Gets freed after its drawn
     792               0 :     fMCRec->fLayer = NULL;
     793                 : 
     794                 :     // now do the normal restore()
     795               0 :     fMCRec->~MCRec();       // balanced in save()
     796               0 :     fMCStack.pop_back();
     797               0 :     fMCRec = (MCRec*)fMCStack.back();
     798                 : 
     799                 :     /*  Time to draw the layer's offscreen. We can't call the public drawSprite,
     800                 :         since if we're being recorded, we don't want to record this (the
     801                 :         recorder will have already recorded the restore).
     802                 :     */
     803               0 :     if (NULL != layer) {
     804               0 :         if (layer->fNext) {
     805               0 :             const SkIPoint& origin = layer->fDevice->getOrigin();
     806                 :             this->drawDevice(layer->fDevice, origin.x(), origin.y(),
     807               0 :                              layer->fPaint);
     808                 :             // reset this, since drawDevice will have set it to true
     809               0 :             fDeviceCMDirty = true;
     810                 : 
     811               0 :             SkASSERT(fLayerCount > 0);
     812               0 :             fLayerCount -= 1;
     813                 :         }
     814               0 :         SkDELETE(layer);
     815                 :     }
     816                 : 
     817               0 :     SkASSERT(fClipStack.getSaveCount() == this->getSaveCount() - 1);
     818               0 : }
     819                 : 
     820               0 : int SkCanvas::getSaveCount() const {
     821               0 :     return fMCStack.count();
     822                 : }
     823                 : 
     824               0 : void SkCanvas::restoreToCount(int count) {
     825                 :     // sanity check
     826               0 :     if (count < 1) {
     827               0 :         count = 1;
     828                 :     }
     829                 :     
     830               0 :     int n = this->getSaveCount() - count;
     831               0 :     for (int i = 0; i < n; ++i) {
     832               0 :         this->restore();
     833                 :     }
     834               0 : }
     835                 : 
     836               0 : bool SkCanvas::isDrawingToLayer() const {
     837               0 :     return fLayerCount > 0;
     838                 : }
     839                 : 
     840                 : /////////////////////////////////////////////////////////////////////////////
     841                 : 
     842                 : // can't draw it if its empty, or its too big for a fixed-point width or height
     843               0 : static bool reject_bitmap(const SkBitmap& bitmap) {
     844               0 :     return  bitmap.width() <= 0 || bitmap.height() <= 0
     845                 : #ifndef SK_ALLOW_OVER_32K_BITMAPS
     846               0 :             || bitmap.width() > 32767 || bitmap.height() > 32767
     847                 : #endif
     848                 :             ;
     849                 : }
     850                 : 
     851               0 : void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect,
     852                 :                                 const SkMatrix& matrix, const SkPaint* paint) {
     853               0 :     if (reject_bitmap(bitmap)) {
     854               0 :         return;
     855                 :     }
     856                 : 
     857               0 :     SkLazyPaint lazy;
     858               0 :     if (NULL == paint) {
     859               0 :         paint = lazy.init();
     860                 :     }
     861               0 :     this->commonDrawBitmap(bitmap, srcRect, matrix, *paint);
     862                 : }
     863                 : 
     864                 : #include "SkImageFilter.h"
     865                 : 
     866                 : class DeviceImageFilterProxy : public SkImageFilter::Proxy {
     867                 : public:
     868               0 :     DeviceImageFilterProxy(SkDevice* device) : fDevice(device) {}
     869                 :     
     870                 :     virtual SkDevice* createDevice(int w, int h) SK_OVERRIDE;
     871                 :     virtual bool filterImage(SkImageFilter*, const SkBitmap& src,
     872                 :                              const SkMatrix& ctm,
     873                 :                              SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
     874                 : 
     875                 : private:
     876                 :     SkDevice* fDevice;
     877                 : };
     878                 : 
     879               0 : SkDevice* DeviceImageFilterProxy::createDevice(int w, int h) {
     880                 :     return fDevice->createCompatibleDevice(SkBitmap::kARGB_8888_Config,
     881               0 :                                            w, h, false);
     882                 : }
     883                 : 
     884               0 : bool DeviceImageFilterProxy::filterImage(SkImageFilter* filter,
     885                 :                                          const SkBitmap& src,
     886                 :                                          const SkMatrix& ctm,
     887                 :                                          SkBitmap* result,
     888                 :                                          SkIPoint* offset) {
     889               0 :     return fDevice->filterImage(filter, src, ctm, result, offset);
     890                 : }
     891                 : 
     892               0 : void SkCanvas::drawDevice(SkDevice* device, int x, int y,
     893                 :                           const SkPaint* paint) {
     894               0 :     SkPaint tmp;
     895               0 :     if (NULL == paint) {
     896               0 :         tmp.setDither(true);
     897               0 :         paint = &tmp;
     898                 :     }
     899                 : 
     900               0 :     LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type)
     901               0 :     while (iter.next()) {
     902               0 :         paint = &looper.paint();
     903               0 :         SkImageFilter* filter = paint->getImageFilter();
     904               0 :         SkIPoint pos = { x - iter.getX(), y - iter.getY() };
     905               0 :         if (filter) {
     906               0 :             DeviceImageFilterProxy proxy(device);
     907               0 :             SkBitmap dst;
     908               0 :             const SkBitmap& src = device->accessBitmap(false);
     909               0 :             if (filter->filterImage(&proxy, src, *iter.fMatrix, &dst, &pos)) {
     910               0 :                 SkPaint tmp(*paint);
     911               0 :                 tmp.setImageFilter(NULL);
     912               0 :                 iter.fDevice->drawSprite(iter, dst, pos.x(), pos.y(), tmp);
     913                 :             }
     914                 :         } else {
     915               0 :             iter.fDevice->drawDevice(iter, device, pos.x(), pos.y(), *paint);
     916                 :         }
     917                 :     }
     918                 :     LOOPER_END
     919               0 : }
     920                 : 
     921                 : /////////////////////////////////////////////////////////////////////////////
     922                 : 
     923               0 : bool SkCanvas::translate(SkScalar dx, SkScalar dy) {
     924               0 :     fDeviceCMDirty = true;
     925               0 :     fLocalBoundsCompareTypeDirty = true;
     926               0 :     fLocalBoundsCompareTypeDirtyBW = true;
     927               0 :     return fMCRec->fMatrix->preTranslate(dx, dy);
     928                 : }
     929                 : 
     930               0 : bool SkCanvas::scale(SkScalar sx, SkScalar sy) {
     931               0 :     fDeviceCMDirty = true;
     932               0 :     fLocalBoundsCompareTypeDirty = true;
     933               0 :     fLocalBoundsCompareTypeDirtyBW = true;
     934               0 :     return fMCRec->fMatrix->preScale(sx, sy);
     935                 : }
     936                 : 
     937               0 : bool SkCanvas::rotate(SkScalar degrees) {
     938               0 :     fDeviceCMDirty = true;
     939               0 :     fLocalBoundsCompareTypeDirty = true;
     940               0 :     fLocalBoundsCompareTypeDirtyBW = true;
     941               0 :     return fMCRec->fMatrix->preRotate(degrees);
     942                 : }
     943                 : 
     944               0 : bool SkCanvas::skew(SkScalar sx, SkScalar sy) {
     945               0 :     fDeviceCMDirty = true;
     946               0 :     fLocalBoundsCompareTypeDirty = true;
     947               0 :     fLocalBoundsCompareTypeDirtyBW = true;
     948               0 :     return fMCRec->fMatrix->preSkew(sx, sy);
     949                 : }
     950                 : 
     951               0 : bool SkCanvas::concat(const SkMatrix& matrix) {
     952               0 :     fDeviceCMDirty = true;
     953               0 :     fLocalBoundsCompareTypeDirty = true;
     954               0 :     fLocalBoundsCompareTypeDirtyBW = true;
     955               0 :     return fMCRec->fMatrix->preConcat(matrix);
     956                 : }
     957                 : 
     958               0 : void SkCanvas::setMatrix(const SkMatrix& matrix) {
     959               0 :     fDeviceCMDirty = true;
     960               0 :     fLocalBoundsCompareTypeDirty = true;
     961               0 :     fLocalBoundsCompareTypeDirtyBW = true;
     962               0 :     *fMCRec->fMatrix = matrix;
     963               0 : }
     964                 : 
     965                 : // this is not virtual, so it must call a virtual method so that subclasses
     966                 : // will see its action
     967               0 : void SkCanvas::resetMatrix() {
     968                 :     SkMatrix matrix;
     969                 : 
     970               0 :     matrix.reset();
     971               0 :     this->setMatrix(matrix);
     972               0 : }
     973                 : 
     974                 : //////////////////////////////////////////////////////////////////////////////
     975                 : 
     976               0 : bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
     977               0 :     AutoValidateClip avc(this);
     978                 : 
     979               0 :     fDeviceCMDirty = true;
     980               0 :     fLocalBoundsCompareTypeDirty = true;
     981               0 :     fLocalBoundsCompareTypeDirtyBW = true;
     982                 : 
     983               0 :     if (fMCRec->fMatrix->rectStaysRect()) {
     984                 :         // for these simpler matrices, we can stay a rect ever after applying
     985                 :         // the matrix. This means we don't have to a) make a path, and b) tell
     986                 :         // the region code to scan-convert the path, only to discover that it
     987                 :         // is really just a rect.
     988                 :         SkRect      r;
     989                 : 
     990               0 :         fMCRec->fMatrix->mapRect(&r, rect);
     991               0 :         fClipStack.clipDevRect(r, op, doAA);
     992               0 :         return fMCRec->fRasterClip->op(r, op, doAA);
     993                 :     } else {
     994                 :         // since we're rotate or some such thing, we convert the rect to a path
     995                 :         // and clip against that, since it can handle any matrix. However, to
     996                 :         // avoid recursion in the case where we are subclassed (e.g. Pictures)
     997                 :         // we explicitly call "our" version of clipPath.
     998               0 :         SkPath  path;
     999                 : 
    1000               0 :         path.addRect(rect);
    1001               0 :         return this->SkCanvas::clipPath(path, op, doAA);
    1002                 :     }
    1003                 : }
    1004                 : 
    1005               0 : static bool clipPathHelper(const SkCanvas* canvas, SkRasterClip* currClip,
    1006                 :                            const SkPath& devPath, SkRegion::Op op, bool doAA) {
    1007                 :     // base is used to limit the size (and therefore memory allocation) of the
    1008                 :     // region that results from scan converting devPath.
    1009               0 :     SkRegion base;
    1010                 : 
    1011               0 :     if (SkRegion::kIntersect_Op == op) {
    1012                 :         // since we are intersect, we can do better (tighter) with currRgn's
    1013                 :         // bounds, than just using the device. However, if currRgn is complex,
    1014                 :         // our region blitter may hork, so we do that case in two steps.
    1015               0 :         if (currClip->isRect()) {
    1016               0 :             return currClip->setPath(devPath, *currClip, doAA);
    1017                 :         } else {
    1018               0 :             base.setRect(currClip->getBounds());
    1019               0 :             SkRasterClip clip;
    1020               0 :             clip.setPath(devPath, base, doAA);
    1021               0 :             return currClip->op(clip, op);
    1022                 :         }
    1023                 :     } else {
    1024               0 :         const SkBitmap& bm = canvas->getDevice()->accessBitmap(false);
    1025               0 :         base.setRect(0, 0, bm.width(), bm.height());
    1026                 : 
    1027               0 :         if (SkRegion::kReplace_Op == op) {
    1028               0 :             return currClip->setPath(devPath, base, doAA);
    1029                 :         } else {
    1030               0 :             SkRasterClip clip;
    1031               0 :             clip.setPath(devPath, base, doAA);
    1032               0 :             return currClip->op(clip, op);
    1033                 :         }
    1034                 :     }
    1035                 : }
    1036                 : 
    1037               0 : bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
    1038               0 :     AutoValidateClip avc(this);
    1039                 : 
    1040               0 :     fDeviceCMDirty = true;
    1041               0 :     fLocalBoundsCompareTypeDirty = true;
    1042               0 :     fLocalBoundsCompareTypeDirtyBW = true;
    1043                 : 
    1044               0 :     SkPath devPath;
    1045               0 :     path.transform(*fMCRec->fMatrix, &devPath);
    1046                 : 
    1047                 :     // Check if the transfomation, or the original path itself
    1048                 :     // made us empty. Note this can also happen if we contained NaN
    1049                 :     // values. computing the bounds detects this, and will set our
    1050                 :     // bounds to empty if that is the case. (see SkRect::set(pts, count))
    1051               0 :     if (devPath.getBounds().isEmpty()) {
    1052                 :         // resetting the path will remove any NaN or other wanky values
    1053                 :         // that might upset our scan converter.
    1054               0 :         devPath.reset();
    1055                 :     }
    1056                 : 
    1057                 :     // if we called path.swap() we could avoid a deep copy of this path
    1058               0 :     fClipStack.clipDevPath(devPath, op, doAA);
    1059                 : 
    1060               0 :     return clipPathHelper(this, fMCRec->fRasterClip, devPath, op, doAA);
    1061                 : }
    1062                 : 
    1063               0 : bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
    1064               0 :     AutoValidateClip avc(this);
    1065                 : 
    1066               0 :     fDeviceCMDirty = true;
    1067               0 :     fLocalBoundsCompareTypeDirty = true;
    1068               0 :     fLocalBoundsCompareTypeDirtyBW = true;
    1069                 : 
    1070                 :     // todo: signal fClipStack that we have a region, and therefore (I guess)
    1071                 :     // we have to ignore it, and use the region directly?
    1072               0 :     fClipStack.clipDevRect(rgn.getBounds());
    1073                 : 
    1074               0 :     return fMCRec->fRasterClip->op(rgn, op);
    1075                 : }
    1076                 : 
    1077                 : #ifdef SK_DEBUG
    1078               0 : void SkCanvas::validateClip() const {
    1079                 :     // construct clipRgn from the clipstack
    1080               0 :     const SkDevice* device = this->getDevice();
    1081                 :     SkIRect ir;
    1082               0 :     ir.set(0, 0, device->width(), device->height());
    1083               0 :     SkRasterClip tmpClip(ir);
    1084                 : 
    1085               0 :     SkClipStack::B2FIter                iter(fClipStack);
    1086                 :     const SkClipStack::B2FIter::Clip*   clip;
    1087               0 :     while ((clip = iter.next()) != NULL) {
    1088               0 :         if (clip->fPath) {
    1089               0 :             clipPathHelper(this, &tmpClip, *clip->fPath, clip->fOp, clip->fDoAA);
    1090               0 :         } else if (clip->fRect) {
    1091               0 :             clip->fRect->round(&ir);
    1092               0 :             tmpClip.op(ir, clip->fOp);
    1093                 :         } else {
    1094               0 :             tmpClip.setEmpty();
    1095                 :         }
    1096                 :     }
    1097                 : 
    1098                 : #if 0   // enable this locally for testing
    1099                 :     // now compare against the current rgn
    1100                 :     const SkRegion& rgn = this->getTotalClip();
    1101                 :     SkASSERT(rgn == tmpClip);
    1102                 : #endif
    1103               0 : }
    1104                 : #endif
    1105                 : 
    1106                 : ///////////////////////////////////////////////////////////////////////////////
    1107                 : 
    1108               0 : void SkCanvas::computeLocalClipBoundsCompareType(EdgeType et) const {
    1109                 :     SkRect r;
    1110                 :     SkRectCompareType& rCompare = et == kAA_EdgeType ? fLocalBoundsCompareType :
    1111               0 :             fLocalBoundsCompareTypeBW;
    1112                 : 
    1113               0 :     if (!this->getClipBounds(&r, et)) {
    1114               0 :         rCompare.setEmpty();
    1115                 :     } else {
    1116                 :         rCompare.set(SkScalarToCompareType(r.fLeft),
    1117                 :                      SkScalarToCompareType(r.fTop),
    1118                 :                      SkScalarToCompareType(r.fRight),
    1119               0 :                      SkScalarToCompareType(r.fBottom));
    1120                 :     }
    1121               0 : }
    1122                 : 
    1123                 : /*  current impl ignores edgetype, and relies on
    1124                 :     getLocalClipBoundsCompareType(), which always returns a value assuming
    1125                 :     antialiasing (worst case)
    1126                 :  */
    1127               0 : bool SkCanvas::quickReject(const SkRect& rect, EdgeType et) const {
    1128                 : 
    1129               0 :     if (!rect.isFinite())
    1130               0 :         return true;
    1131                 : 
    1132               0 :     if (fMCRec->fRasterClip->isEmpty()) {
    1133               0 :         return true;
    1134                 :     }
    1135                 : 
    1136               0 :     if (fMCRec->fMatrix->hasPerspective()) {
    1137                 :         SkRect dst;
    1138               0 :         fMCRec->fMatrix->mapRect(&dst, rect);
    1139                 :         SkIRect idst;
    1140               0 :         dst.roundOut(&idst);
    1141               0 :         return !SkIRect::Intersects(idst, fMCRec->fRasterClip->getBounds());
    1142                 :     } else {
    1143               0 :         const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType(et);
    1144                 : 
    1145                 :         // for speed, do the most likely reject compares first
    1146               0 :         SkScalarCompareType userT = SkScalarToCompareType(rect.fTop);
    1147               0 :         SkScalarCompareType userB = SkScalarToCompareType(rect.fBottom);
    1148               0 :         if (userT >= clipR.fBottom || userB <= clipR.fTop) {
    1149               0 :             return true;
    1150                 :         }
    1151               0 :         SkScalarCompareType userL = SkScalarToCompareType(rect.fLeft);
    1152               0 :         SkScalarCompareType userR = SkScalarToCompareType(rect.fRight);
    1153               0 :         if (userL >= clipR.fRight || userR <= clipR.fLeft) {
    1154               0 :             return true;
    1155                 :         }
    1156               0 :         return false;
    1157                 :     }
    1158                 : }
    1159                 : 
    1160               0 : bool SkCanvas::quickReject(const SkPath& path, EdgeType et) const {
    1161               0 :     return path.isEmpty() || this->quickReject(path.getBounds(), et);
    1162                 : }
    1163                 : 
    1164               0 : bool SkCanvas::quickRejectY(SkScalar top, SkScalar bottom, EdgeType et) const {
    1165                 :     /*  current impl ignores edgetype, and relies on
    1166                 :         getLocalClipBoundsCompareType(), which always returns a value assuming
    1167                 :         antialiasing (worst case)
    1168                 :      */
    1169                 : 
    1170               0 :     if (fMCRec->fRasterClip->isEmpty()) {
    1171               0 :         return true;
    1172                 :     }
    1173                 : 
    1174               0 :     SkScalarCompareType userT = SkScalarToCompareType(top);
    1175               0 :     SkScalarCompareType userB = SkScalarToCompareType(bottom);
    1176                 : 
    1177                 :     // check for invalid user Y coordinates (i.e. empty)
    1178                 :     // reed: why do we need to do this check, since it slows us down?
    1179               0 :     if (userT >= userB) {
    1180               0 :         return true;
    1181                 :     }
    1182                 : 
    1183                 :     // check if we are above or below the local clip bounds
    1184               0 :     const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType();
    1185               0 :     return userT >= clipR.fBottom || userB <= clipR.fTop;
    1186                 : }
    1187                 : 
    1188               0 : bool SkCanvas::getClipBounds(SkRect* bounds, EdgeType et) const {
    1189                 :     SkIRect ibounds;
    1190               0 :     if (!getClipDeviceBounds(&ibounds)) {
    1191               0 :         return false;
    1192                 :     }
    1193                 : 
    1194                 :     SkMatrix inverse;
    1195                 :     // if we can't invert the CTM, we can't return local clip bounds
    1196               0 :     if (!fMCRec->fMatrix->invert(&inverse)) {
    1197               0 :         if (bounds) {
    1198               0 :             bounds->setEmpty();
    1199                 :         }
    1200               0 :         return false;
    1201                 :     }
    1202                 : 
    1203               0 :     if (NULL != bounds) {
    1204                 :         SkRect r;
    1205                 :         // adjust it outwards if we are antialiasing
    1206               0 :         int inset = (kAA_EdgeType == et);
    1207                 :         r.iset(ibounds.fLeft - inset,  ibounds.fTop - inset,
    1208               0 :                ibounds.fRight + inset, ibounds.fBottom + inset);
    1209               0 :         inverse.mapRect(bounds, r);
    1210                 :     }
    1211               0 :     return true;
    1212                 : }
    1213                 : 
    1214               0 : bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
    1215               0 :     const SkRasterClip& clip = *fMCRec->fRasterClip;
    1216               0 :     if (clip.isEmpty()) {
    1217               0 :         if (bounds) {
    1218               0 :             bounds->setEmpty();
    1219                 :         }
    1220               0 :         return false;
    1221                 :     }
    1222                 : 
    1223               0 :     if (NULL != bounds) {
    1224               0 :         *bounds = clip.getBounds();
    1225                 :     }
    1226               0 :     return true;
    1227                 : }
    1228                 : 
    1229               0 : const SkMatrix& SkCanvas::getTotalMatrix() const {
    1230               0 :     return *fMCRec->fMatrix;
    1231                 : }
    1232                 : 
    1233               0 : SkCanvas::ClipType SkCanvas::getClipType() const {
    1234               0 :     if (fMCRec->fRasterClip->isEmpty()) return kEmpty_ClipType;
    1235               0 :     if (fMCRec->fRasterClip->isRect()) return kRect_ClipType;
    1236               0 :     return kComplex_ClipType;
    1237                 : }
    1238                 : 
    1239               0 : const SkRegion& SkCanvas::getTotalClip() const {
    1240               0 :     return fMCRec->fRasterClip->forceGetBW();
    1241                 : }
    1242                 : 
    1243               0 : const SkClipStack& SkCanvas::getTotalClipStack() const {
    1244               0 :     return fClipStack;
    1245                 : }
    1246                 : 
    1247               0 : void SkCanvas::setExternalMatrix(const SkMatrix* matrix) {
    1248               0 :     if (NULL == matrix || matrix->isIdentity()) {
    1249               0 :         if (fUseExternalMatrix) {
    1250               0 :             fDeviceCMDirty = true;
    1251                 :         }
    1252               0 :         fUseExternalMatrix = false;
    1253                 :     } else {
    1254               0 :         fUseExternalMatrix = true;
    1255               0 :         fDeviceCMDirty = true;  // |= (fExternalMatrix != *matrix)
    1256                 : 
    1257               0 :         fExternalMatrix = *matrix;
    1258               0 :         matrix->invert(&fExternalInverse);
    1259                 :     }
    1260               0 : }
    1261                 : 
    1262               0 : SkDevice* SkCanvas::createLayerDevice(SkBitmap::Config config,
    1263                 :                                       int width, int height,
    1264                 :                                       bool isOpaque) {
    1265               0 :     SkDevice* device = this->getTopDevice();
    1266               0 :     if (device) {
    1267                 :         return device->createCompatibleDeviceForSaveLayer(config, width, height,
    1268               0 :                                                           isOpaque);
    1269                 :     } else {
    1270               0 :         return NULL;
    1271                 :     }
    1272                 : }
    1273                 : 
    1274               0 : SkDevice* SkCanvas::createCompatibleDevice(SkBitmap::Config config, 
    1275                 :                                            int width, int height,
    1276                 :                                            bool isOpaque) {
    1277               0 :     SkDevice* device = this->getDevice();
    1278               0 :     if (device) {
    1279               0 :         return device->createCompatibleDevice(config, width, height, isOpaque);
    1280                 :     } else {
    1281               0 :         return NULL;
    1282                 :     }
    1283                 : }
    1284                 : 
    1285                 : 
    1286                 : //////////////////////////////////////////////////////////////////////////////
    1287                 : //  These are the virtual drawing methods
    1288                 : //////////////////////////////////////////////////////////////////////////////
    1289                 : 
    1290               0 : void SkCanvas::clear(SkColor color) {
    1291               0 :     SkDrawIter  iter(this);
    1292                 : 
    1293               0 :     while (iter.next()) {
    1294               0 :         iter.fDevice->clear(color);
    1295                 :     }
    1296               0 : }
    1297                 : 
    1298               0 : void SkCanvas::drawPaint(const SkPaint& paint) {
    1299               0 :     this->internalDrawPaint(paint);
    1300               0 : }
    1301                 : 
    1302               0 : void SkCanvas::internalDrawPaint(const SkPaint& paint) {
    1303               0 :     LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type)
    1304                 : 
    1305               0 :     while (iter.next()) {
    1306               0 :         iter.fDevice->drawPaint(iter, looper.paint());
    1307                 :     }
    1308                 : 
    1309                 :     LOOPER_END
    1310               0 : }
    1311                 : 
    1312               0 : void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
    1313                 :                           const SkPaint& paint) {
    1314               0 :     if ((long)count <= 0) {
    1315               0 :         return;
    1316                 :     }
    1317                 : 
    1318               0 :     SkASSERT(pts != NULL);
    1319                 : 
    1320               0 :     LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type)
    1321                 : 
    1322               0 :     while (iter.next()) {
    1323               0 :         iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
    1324                 :     }
    1325                 : 
    1326                 :     LOOPER_END
    1327                 : }
    1328                 : 
    1329               0 : void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
    1330               0 :     if (paint.canComputeFastBounds()) {
    1331                 :         SkRect storage;
    1332               0 :         if (this->quickReject(paint.computeFastBounds(r, &storage),
    1333               0 :                               paint2EdgeType(&paint))) {
    1334               0 :             return;
    1335                 :         }
    1336                 :     }
    1337                 : 
    1338               0 :     LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type)
    1339                 : 
    1340               0 :     while (iter.next()) {
    1341               0 :         iter.fDevice->drawRect(iter, r, looper.paint());
    1342                 :     }
    1343                 : 
    1344                 :     LOOPER_END
    1345                 : }
    1346                 : 
    1347               0 : void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
    1348               0 :     if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
    1349                 :         SkRect storage;
    1350               0 :         const SkRect& bounds = path.getBounds();
    1351               0 :         if (this->quickReject(paint.computeFastBounds(bounds, &storage),
    1352               0 :                               paint2EdgeType(&paint))) {
    1353               0 :             return;
    1354                 :         }
    1355                 :     }
    1356               0 :     if (path.isEmpty()) {
    1357               0 :         if (path.isInverseFillType()) {
    1358               0 :             this->internalDrawPaint(paint);
    1359                 :         }
    1360               0 :         return;
    1361                 :     }
    1362                 : 
    1363               0 :     LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type)
    1364                 : 
    1365               0 :     while (iter.next()) {
    1366               0 :         iter.fDevice->drawPath(iter, path, looper.paint());
    1367                 :     }
    1368                 : 
    1369                 :     LOOPER_END
    1370                 : }
    1371                 : 
    1372               0 : void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
    1373                 :                           const SkPaint* paint) {
    1374               0 :     SkDEBUGCODE(bitmap.validate();)
    1375                 : 
    1376               0 :     if (NULL == paint || paint->canComputeFastBounds()) {
    1377                 :         SkRect fastBounds;
    1378                 :         fastBounds.set(x, y,
    1379               0 :                        x + SkIntToScalar(bitmap.width()),
    1380               0 :                        y + SkIntToScalar(bitmap.height()));
    1381               0 :         if (this->quickReject(fastBounds, paint2EdgeType(paint))) {
    1382               0 :             return;
    1383                 :         }
    1384                 :     }
    1385                 : 
    1386                 :     SkMatrix matrix;
    1387               0 :     matrix.setTranslate(x, y);
    1388               0 :     this->internalDrawBitmap(bitmap, NULL, matrix, paint);
    1389                 : }
    1390                 : 
    1391                 : // this one is non-virtual, so it can be called safely by other canvas apis
    1392               0 : void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
    1393                 :                                       const SkRect& dst, const SkPaint* paint) {
    1394               0 :     if (bitmap.width() == 0 || bitmap.height() == 0 || dst.isEmpty()) {
    1395               0 :         return;
    1396                 :     }
    1397                 :     
    1398                 :     // do this now, to avoid the cost of calling extract for RLE bitmaps
    1399               0 :     if (NULL == paint || paint->canComputeFastBounds()) {
    1400               0 :         if (this->quickReject(dst, paint2EdgeType(paint))) {
    1401               0 :             return;
    1402                 :         }
    1403                 :     }
    1404                 : 
    1405               0 :     const SkBitmap* bitmapPtr = &bitmap;
    1406                 :     
    1407                 :     SkMatrix matrix;
    1408                 :     SkRect tmpSrc;
    1409               0 :     if (src) {
    1410               0 :         tmpSrc.set(*src);
    1411                 :         // if the extract process clipped off the top or left of the
    1412                 :         // original, we adjust for that here to get the position right.
    1413               0 :         if (tmpSrc.fLeft > 0) {
    1414               0 :             tmpSrc.fRight -= tmpSrc.fLeft;
    1415               0 :             tmpSrc.fLeft = 0;
    1416                 :         }
    1417               0 :         if (tmpSrc.fTop > 0) {
    1418               0 :             tmpSrc.fBottom -= tmpSrc.fTop;
    1419               0 :             tmpSrc.fTop = 0;
    1420                 :         }
    1421                 :     } else {
    1422                 :         tmpSrc.set(0, 0, SkIntToScalar(bitmap.width()),
    1423               0 :                    SkIntToScalar(bitmap.height()));
    1424                 :     }
    1425               0 :     matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
    1426                 :     
    1427                 :     // ensure that src is "valid" before we pass it to our internal routines
    1428                 :     // and to SkDevice. i.e. sure it is contained inside the original bitmap.
    1429                 :     SkIRect tmpISrc;
    1430               0 :     if (src) {
    1431               0 :         tmpISrc.set(0, 0, bitmap.width(), bitmap.height());
    1432               0 :         if (!tmpISrc.intersect(*src)) {
    1433               0 :             return;
    1434                 :         }
    1435               0 :         src = &tmpISrc;
    1436                 :     }
    1437               0 :     this->internalDrawBitmap(*bitmapPtr, src, matrix, paint);
    1438                 : }
    1439                 : 
    1440               0 : void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
    1441                 :                               const SkRect& dst, const SkPaint* paint) {
    1442               0 :     SkDEBUGCODE(bitmap.validate();)
    1443               0 :     this->internalDrawBitmapRect(bitmap, src, dst, paint);
    1444               0 : }
    1445                 : 
    1446               0 : void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
    1447                 :                                 const SkPaint* paint) {
    1448               0 :     SkDEBUGCODE(bitmap.validate();)
    1449               0 :     this->internalDrawBitmap(bitmap, NULL, matrix, paint);
    1450               0 : }
    1451                 : 
    1452               0 : void SkCanvas::commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect,
    1453                 :                                 const SkMatrix& matrix, const SkPaint& paint) {
    1454               0 :     SkDEBUGCODE(bitmap.validate();)
    1455                 : 
    1456               0 :     LOOPER_BEGIN(paint, SkDrawFilter::kBitmap_Type)
    1457                 : 
    1458               0 :     while (iter.next()) {
    1459               0 :         iter.fDevice->drawBitmap(iter, bitmap, srcRect, matrix, looper.paint());
    1460                 :     }
    1461                 : 
    1462                 :     LOOPER_END
    1463               0 : }
    1464                 : 
    1465               0 : void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
    1466                 :                                       const SkIRect& center, const SkRect& dst,
    1467                 :                                       const SkPaint* paint) {
    1468               0 :     if (NULL == paint || paint->canComputeFastBounds()) {
    1469               0 :         if (this->quickReject(dst, paint2EdgeType(paint))) {
    1470               0 :             return;
    1471                 :         }
    1472                 :     }
    1473                 : 
    1474               0 :     const int32_t w = bitmap.width();
    1475               0 :     const int32_t h = bitmap.height();
    1476                 : 
    1477               0 :     SkIRect c = center;
    1478                 :     // pin center to the bounds of the bitmap
    1479               0 :     c.fLeft = SkMax32(0, center.fLeft);
    1480               0 :     c.fTop = SkMax32(0, center.fTop);
    1481               0 :     c.fRight = SkPin32(center.fRight, c.fLeft, w);
    1482               0 :     c.fBottom = SkPin32(center.fBottom, c.fTop, h);
    1483                 : 
    1484               0 :     const int32_t srcX[4] = { 0, c.fLeft, c.fRight, w };
    1485               0 :     const int32_t srcY[4] = { 0, c.fTop, c.fBottom, h };
    1486                 :     SkScalar dstX[4] = {
    1487               0 :         dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
    1488               0 :         dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
    1489               0 :     };
    1490                 :     SkScalar dstY[4] = {
    1491               0 :         dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
    1492               0 :         dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
    1493               0 :     };
    1494                 :     
    1495               0 :     if (dstX[1] > dstX[2]) {
    1496               0 :         dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
    1497               0 :         dstX[2] = dstX[1];
    1498                 :     }
    1499                 :     
    1500               0 :     if (dstY[1] > dstY[2]) {
    1501               0 :         dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
    1502               0 :         dstY[2] = dstY[1];
    1503                 :     }
    1504                 :     
    1505                 :     SkIRect s;
    1506                 :     SkRect  d;
    1507               0 :     for (int y = 0; y < 3; y++) {
    1508               0 :         s.fTop = srcY[y];
    1509               0 :         s.fBottom = srcY[y+1];
    1510               0 :         d.fTop = dstY[y];
    1511               0 :         d.fBottom = dstY[y+1];
    1512               0 :         for (int x = 0; x < 3; x++) {
    1513               0 :             s.fLeft = srcX[x];
    1514               0 :             s.fRight = srcX[x+1];
    1515               0 :             d.fLeft = dstX[x];
    1516               0 :             d.fRight = dstX[x+1];
    1517               0 :             this->internalDrawBitmapRect(bitmap, &s, d, paint);
    1518                 :         }
    1519                 :     }
    1520                 : }
    1521                 : 
    1522               0 : void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
    1523                 :                               const SkRect& dst, const SkPaint* paint) {
    1524               0 :     SkDEBUGCODE(bitmap.validate();)
    1525                 : 
    1526                 :     // Need a device entry-point, so gpu can use a mesh
    1527               0 :     this->internalDrawBitmapNine(bitmap, center, dst, paint);
    1528               0 : }
    1529                 : 
    1530               0 : void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y,
    1531                 :                           const SkPaint* paint) {
    1532               0 :     SkDEBUGCODE(bitmap.validate();)
    1533                 : 
    1534               0 :     if (reject_bitmap(bitmap)) {
    1535               0 :         return;
    1536                 :     }
    1537                 : 
    1538               0 :     SkPaint tmp;
    1539               0 :     if (NULL == paint) {
    1540               0 :         paint = &tmp;
    1541                 :     }
    1542                 : 
    1543               0 :     LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type)
    1544                 : 
    1545               0 :     while (iter.next()) {
    1546               0 :         iter.fDevice->drawSprite(iter, bitmap, x - iter.getX(), y - iter.getY(),
    1547               0 :                                  looper.paint());
    1548                 :     }
    1549                 :     LOOPER_END
    1550                 : }
    1551                 : 
    1552               0 : class SkDeviceFilteredPaint {
    1553                 : public:
    1554               0 :     SkDeviceFilteredPaint(SkDevice* device, const SkPaint& paint) {
    1555                 :         SkDevice::TextFlags flags;
    1556               0 :         if (device->filterTextFlags(paint, &flags)) {
    1557               0 :             SkPaint* newPaint = fLazy.set(paint);
    1558               0 :             newPaint->setFlags(flags.fFlags);
    1559               0 :             newPaint->setHinting(flags.fHinting);
    1560               0 :             fPaint = newPaint;
    1561                 :         } else {
    1562               0 :             fPaint = &paint;
    1563                 :         }
    1564               0 :     }
    1565                 : 
    1566               0 :     const SkPaint& paint() const { return *fPaint; }
    1567                 : 
    1568                 : private:
    1569                 :     const SkPaint*  fPaint;
    1570                 :     SkLazyPaint     fLazy;
    1571                 : };
    1572                 : 
    1573               0 : void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
    1574                 :                         const SkRect& r, SkScalar textSize) {
    1575               0 :     if (paint.getStyle() == SkPaint::kFill_Style) {
    1576               0 :         draw.fDevice->drawRect(draw, r, paint);
    1577                 :     } else {
    1578               0 :         SkPaint p(paint);
    1579               0 :         p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
    1580               0 :         draw.fDevice->drawRect(draw, r, p);
    1581                 :     }
    1582               0 : }
    1583                 : 
    1584               0 : void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
    1585                 :                                    const char text[], size_t byteLength,
    1586                 :                                    SkScalar x, SkScalar y) {
    1587               0 :     SkASSERT(byteLength == 0 || text != NULL);
    1588                 : 
    1589                 :     // nothing to draw
    1590               0 :     if (text == NULL || byteLength == 0 ||
    1591               0 :         draw.fClip->isEmpty() ||
    1592               0 :         (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
    1593               0 :         return;
    1594                 :     }
    1595                 : 
    1596               0 :     SkScalar    width = 0;
    1597                 :     SkPoint     start;
    1598                 : 
    1599               0 :     start.set(0, 0);    // to avoid warning
    1600               0 :     if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
    1601                 :                             SkPaint::kStrikeThruText_Flag)) {
    1602               0 :         width = paint.measureText(text, byteLength);
    1603                 : 
    1604               0 :         SkScalar offsetX = 0;
    1605               0 :         if (paint.getTextAlign() == SkPaint::kCenter_Align) {
    1606               0 :             offsetX = SkScalarHalf(width);
    1607               0 :         } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
    1608               0 :             offsetX = width;
    1609                 :         }
    1610               0 :         start.set(x - offsetX, y);
    1611                 :     }
    1612                 : 
    1613               0 :     if (0 == width) {
    1614               0 :         return;
    1615                 :     }
    1616                 : 
    1617               0 :     uint32_t flags = paint.getFlags();
    1618                 : 
    1619               0 :     if (flags & (SkPaint::kUnderlineText_Flag |
    1620                 :                  SkPaint::kStrikeThruText_Flag)) {
    1621               0 :         SkScalar textSize = paint.getTextSize();
    1622               0 :         SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
    1623                 :         SkRect   r;
    1624                 : 
    1625               0 :         r.fLeft = start.fX;
    1626               0 :         r.fRight = start.fX + width;
    1627                 : 
    1628               0 :         if (flags & SkPaint::kUnderlineText_Flag) {
    1629               0 :             SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
    1630                 :                                              start.fY);
    1631               0 :             r.fTop = offset;
    1632               0 :             r.fBottom = offset + height;
    1633               0 :             DrawRect(draw, paint, r, textSize);
    1634                 :         }
    1635               0 :         if (flags & SkPaint::kStrikeThruText_Flag) {
    1636               0 :             SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
    1637                 :                                              start.fY);
    1638               0 :             r.fTop = offset;
    1639               0 :             r.fBottom = offset + height;
    1640               0 :             DrawRect(draw, paint, r, textSize);
    1641                 :         }
    1642                 :     }
    1643                 : }
    1644                 : 
    1645               0 : void SkCanvas::drawText(const void* text, size_t byteLength,
    1646                 :                         SkScalar x, SkScalar y, const SkPaint& paint) {
    1647               0 :     LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
    1648                 : 
    1649               0 :     while (iter.next()) {
    1650               0 :         SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
    1651               0 :         iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
    1652               0 :         DrawTextDecorations(iter, dfp.paint(),
    1653               0 :                             static_cast<const char*>(text), byteLength, x, y);
    1654                 :     }
    1655                 : 
    1656                 :     LOOPER_END
    1657               0 : }
    1658                 : 
    1659               0 : void SkCanvas::drawPosText(const void* text, size_t byteLength,
    1660                 :                            const SkPoint pos[], const SkPaint& paint) {
    1661               0 :     LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
    1662                 : 
    1663               0 :     while (iter.next()) {
    1664               0 :         SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
    1665                 :         iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2,
    1666               0 :                                   dfp.paint());
    1667                 :     }
    1668                 : 
    1669                 :     LOOPER_END
    1670               0 : }
    1671                 : 
    1672               0 : void SkCanvas::drawPosTextH(const void* text, size_t byteLength,
    1673                 :                             const SkScalar xpos[], SkScalar constY,
    1674                 :                             const SkPaint& paint) {
    1675               0 :     LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
    1676                 : 
    1677               0 :     while (iter.next()) {
    1678               0 :         SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
    1679                 :         iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1,
    1680               0 :                                   dfp.paint());
    1681                 :     }
    1682                 : 
    1683                 :     LOOPER_END
    1684               0 : }
    1685                 : 
    1686               0 : void SkCanvas::drawTextOnPath(const void* text, size_t byteLength,
    1687                 :                               const SkPath& path, const SkMatrix* matrix,
    1688                 :                               const SkPaint& paint) {
    1689               0 :     LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
    1690                 : 
    1691               0 :     while (iter.next()) {
    1692                 :         iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
    1693               0 :                                      matrix, looper.paint());
    1694                 :     }
    1695                 : 
    1696                 :     LOOPER_END
    1697               0 : }
    1698                 : 
    1699                 : #ifdef SK_BUILD_FOR_ANDROID
    1700                 : void SkCanvas::drawPosTextOnPath(const void* text, size_t byteLength,
    1701                 :                                  const SkPoint pos[], const SkPaint& paint,
    1702                 :                                  const SkPath& path, const SkMatrix* matrix) {
    1703                 :     LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
    1704                 : 
    1705                 :     while (iter.next()) {
    1706                 :         iter.fDevice->drawPosTextOnPath(iter, text, byteLength, pos,
    1707                 :                                         looper.paint(), path, matrix);
    1708                 :     }
    1709                 : 
    1710                 :     LOOPER_END
    1711                 : }
    1712                 : #endif
    1713                 : 
    1714               0 : void SkCanvas::drawVertices(VertexMode vmode, int vertexCount,
    1715                 :                             const SkPoint verts[], const SkPoint texs[],
    1716                 :                             const SkColor colors[], SkXfermode* xmode,
    1717                 :                             const uint16_t indices[], int indexCount,
    1718                 :                             const SkPaint& paint) {
    1719               0 :     LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type)
    1720                 : 
    1721               0 :     while (iter.next()) {
    1722                 :         iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
    1723                 :                                    colors, xmode, indices, indexCount,
    1724               0 :                                    looper.paint());
    1725                 :     }
    1726                 : 
    1727                 :     LOOPER_END
    1728               0 : }
    1729                 : 
    1730               0 : void SkCanvas::drawData(const void* data, size_t length) {
    1731                 :     // do nothing. Subclasses may do something with the data
    1732               0 : }
    1733                 : 
    1734                 : //////////////////////////////////////////////////////////////////////////////
    1735                 : // These methods are NOT virtual, and therefore must call back into virtual
    1736                 : // methods, rather than actually drawing themselves.
    1737                 : //////////////////////////////////////////////////////////////////////////////
    1738                 : 
    1739               0 : void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
    1740                 :                         SkXfermode::Mode mode) {
    1741               0 :     SkPaint paint;
    1742                 : 
    1743               0 :     paint.setARGB(a, r, g, b);
    1744               0 :     if (SkXfermode::kSrcOver_Mode != mode) {
    1745               0 :         paint.setXfermodeMode(mode);
    1746                 :     }
    1747               0 :     this->drawPaint(paint);
    1748               0 : }
    1749                 : 
    1750               0 : void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
    1751               0 :     SkPaint paint;
    1752                 : 
    1753               0 :     paint.setColor(c);
    1754               0 :     if (SkXfermode::kSrcOver_Mode != mode) {
    1755               0 :         paint.setXfermodeMode(mode);
    1756                 :     }
    1757               0 :     this->drawPaint(paint);
    1758               0 : }
    1759                 : 
    1760               0 : void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
    1761                 :     SkPoint pt;
    1762                 : 
    1763               0 :     pt.set(x, y);
    1764               0 :     this->drawPoints(kPoints_PointMode, 1, &pt, paint);
    1765               0 : }
    1766                 : 
    1767               0 : void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
    1768                 :     SkPoint pt;
    1769               0 :     SkPaint paint;
    1770                 : 
    1771               0 :     pt.set(x, y);
    1772               0 :     paint.setColor(color);
    1773               0 :     this->drawPoints(kPoints_PointMode, 1, &pt, paint);
    1774               0 : }
    1775                 : 
    1776               0 : void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
    1777                 :                         const SkPaint& paint) {
    1778                 :     SkPoint pts[2];
    1779                 : 
    1780               0 :     pts[0].set(x0, y0);
    1781               0 :     pts[1].set(x1, y1);
    1782               0 :     this->drawPoints(kLines_PointMode, 2, pts, paint);
    1783               0 : }
    1784                 : 
    1785               0 : void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
    1786                 :                               SkScalar right, SkScalar bottom,
    1787                 :                               const SkPaint& paint) {
    1788                 :     SkRect  r;
    1789                 : 
    1790               0 :     r.set(left, top, right, bottom);
    1791               0 :     this->drawRect(r, paint);
    1792               0 : }
    1793                 : 
    1794               0 : void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
    1795                 :                           const SkPaint& paint) {
    1796               0 :     if (radius < 0) {
    1797               0 :         radius = 0;
    1798                 :     }
    1799                 : 
    1800                 :     SkRect  r;
    1801               0 :     r.set(cx - radius, cy - radius, cx + radius, cy + radius);
    1802                 : 
    1803               0 :     if (paint.canComputeFastBounds()) {
    1804                 :         SkRect storage;
    1805               0 :         if (this->quickReject(paint.computeFastBounds(r, &storage),
    1806               0 :                               paint2EdgeType(&paint))) {
    1807               0 :             return;
    1808                 :         }
    1809                 :     }
    1810                 : 
    1811               0 :     SkPath  path;
    1812               0 :     path.addOval(r);
    1813               0 :     this->drawPath(path, paint);
    1814                 : }
    1815                 : 
    1816               0 : void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
    1817                 :                              const SkPaint& paint) {
    1818               0 :     if (rx > 0 && ry > 0) {
    1819               0 :         if (paint.canComputeFastBounds()) {
    1820                 :             SkRect storage;
    1821               0 :             if (this->quickReject(paint.computeFastBounds(r, &storage),
    1822               0 :                                   paint2EdgeType(&paint))) {
    1823               0 :                 return;
    1824                 :             }
    1825                 :         }
    1826                 : 
    1827               0 :         SkPath  path;
    1828               0 :         path.addRoundRect(r, rx, ry, SkPath::kCW_Direction);
    1829               0 :         this->drawPath(path, paint);
    1830                 :     } else {
    1831               0 :         this->drawRect(r, paint);
    1832                 :     }
    1833                 : }
    1834                 : 
    1835               0 : void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
    1836               0 :     if (paint.canComputeFastBounds()) {
    1837                 :         SkRect storage;
    1838               0 :         if (this->quickReject(paint.computeFastBounds(oval, &storage),
    1839               0 :                               paint2EdgeType(&paint))) {
    1840               0 :             return;
    1841                 :         }
    1842                 :     }
    1843                 : 
    1844               0 :     SkPath  path;
    1845               0 :     path.addOval(oval);
    1846               0 :     this->drawPath(path, paint);
    1847                 : }
    1848                 : 
    1849               0 : void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
    1850                 :                        SkScalar sweepAngle, bool useCenter,
    1851                 :                        const SkPaint& paint) {
    1852               0 :     if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
    1853               0 :         this->drawOval(oval, paint);
    1854                 :     } else {
    1855               0 :         SkPath  path;
    1856               0 :         if (useCenter) {
    1857               0 :             path.moveTo(oval.centerX(), oval.centerY());
    1858                 :         }
    1859               0 :         path.arcTo(oval, startAngle, sweepAngle, !useCenter);
    1860               0 :         if (useCenter) {
    1861               0 :             path.close();
    1862                 :         }
    1863               0 :         this->drawPath(path, paint);
    1864                 :     }
    1865               0 : }
    1866                 : 
    1867               0 : void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
    1868                 :                                 const SkPath& path, SkScalar hOffset,
    1869                 :                                 SkScalar vOffset, const SkPaint& paint) {
    1870                 :     SkMatrix    matrix;
    1871                 : 
    1872               0 :     matrix.setTranslate(hOffset, vOffset);
    1873               0 :     this->drawTextOnPath(text, byteLength, path, &matrix, paint);
    1874               0 : }
    1875                 : 
    1876                 : ///////////////////////////////////////////////////////////////////////////////
    1877                 : 
    1878               0 : void SkCanvas::drawPicture(SkPicture& picture) {
    1879               0 :     int saveCount = save();
    1880               0 :     picture.draw(this);
    1881               0 :     restoreToCount(saveCount);
    1882               0 : }
    1883                 : 
    1884                 : ///////////////////////////////////////////////////////////////////////////////
    1885                 : ///////////////////////////////////////////////////////////////////////////////
    1886                 : 
    1887               0 : SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
    1888                 :     SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
    1889                 : 
    1890               0 :     SkASSERT(canvas);
    1891                 : 
    1892               0 :     fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
    1893               0 :     fDone = !fImpl->next();
    1894               0 : }
    1895                 : 
    1896               0 : SkCanvas::LayerIter::~LayerIter() {
    1897               0 :     fImpl->~SkDrawIter();
    1898               0 : }
    1899                 : 
    1900               0 : void SkCanvas::LayerIter::next() {
    1901               0 :     fDone = !fImpl->next();
    1902               0 : }
    1903                 : 
    1904               0 : SkDevice* SkCanvas::LayerIter::device() const {
    1905               0 :     return fImpl->getDevice();
    1906                 : }
    1907                 : 
    1908               0 : const SkMatrix& SkCanvas::LayerIter::matrix() const {
    1909               0 :     return fImpl->getMatrix();
    1910                 : }
    1911                 : 
    1912               0 : const SkPaint& SkCanvas::LayerIter::paint() const {
    1913               0 :     const SkPaint* paint = fImpl->getPaint();
    1914               0 :     if (NULL == paint) {
    1915               0 :         paint = &fDefaultPaint;
    1916                 :     }
    1917               0 :     return *paint;
    1918                 : }
    1919                 : 
    1920               0 : const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
    1921               0 : int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
    1922            4392 : int SkCanvas::LayerIter::y() const { return fImpl->getY(); }

Generated by: LCOV version 1.7