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

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