gfx/skia/trunk/src/core/SkCanvas.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     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  */
    10 #include "SkCanvas.h"
    11 #include "SkBitmapDevice.h"
    12 #include "SkBounder.h"
    13 #include "SkDeviceImageFilterProxy.h"
    14 #include "SkDraw.h"
    15 #include "SkDrawFilter.h"
    16 #include "SkDrawLooper.h"
    17 #include "SkMetaData.h"
    18 #include "SkPathOps.h"
    19 #include "SkPicture.h"
    20 #include "SkRasterClip.h"
    21 #include "SkRRect.h"
    22 #include "SkSmallAllocator.h"
    23 #include "SkSurface_Base.h"
    24 #include "SkTemplates.h"
    25 #include "SkTextFormatParams.h"
    26 #include "SkTLazy.h"
    27 #include "SkUtils.h"
    29 #if SK_SUPPORT_GPU
    30 #include "GrRenderTarget.h"
    31 #endif
    33 // experimental for faster tiled drawing...
    34 //#define SK_ENABLE_CLIP_QUICKREJECT
    36 //#define SK_TRACE_SAVERESTORE
    38 #ifdef SK_TRACE_SAVERESTORE
    39     static int gLayerCounter;
    40     static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
    41     static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
    43     static int gRecCounter;
    44     static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
    45     static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
    47     static int gCanvasCounter;
    48     static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
    49     static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
    50 #else
    51     #define inc_layer()
    52     #define dec_layer()
    53     #define inc_rec()
    54     #define dec_rec()
    55     #define inc_canvas()
    56     #define dec_canvas()
    57 #endif
    59 #ifdef SK_DEBUG
    60 #include "SkPixelRef.h"
    62 /*
    63  *  Some pixelref subclasses can support being "locked" from another thread
    64  *  during the lock-scope of skia calling them. In these instances, this balance
    65  *  check will fail, but may not be indicative of a problem, so we allow a build
    66  *  flag to disable this check.
    67  *
    68  *  Potentially another fix would be to have a (debug-only) virtual or flag on
    69  *  pixelref, which could tell us at runtime if this check is valid. That would
    70  *  eliminate the need for this heavy-handed build check.
    71  */
    72 #ifdef SK_DISABLE_PIXELREF_LOCKCOUNT_BALANCE_CHECK
    73 class AutoCheckLockCountBalance {
    74 public:
    75     AutoCheckLockCountBalance(const SkBitmap&) { /* do nothing */ }
    76 };
    77 #else
    78 class AutoCheckLockCountBalance {
    79 public:
    80     AutoCheckLockCountBalance(const SkBitmap& bm) : fPixelRef(bm.pixelRef()) {
    81         fLockCount = fPixelRef ? fPixelRef->getLockCount() : 0;
    82     }
    83     ~AutoCheckLockCountBalance() {
    84         const int count = fPixelRef ? fPixelRef->getLockCount() : 0;
    85         SkASSERT(count == fLockCount);
    86     }
    88 private:
    89     const SkPixelRef* fPixelRef;
    90     int               fLockCount;
    91 };
    92 #endif
    94 class AutoCheckNoSetContext {
    95 public:
    96     AutoCheckNoSetContext(const SkPaint& paint) : fPaint(paint) {
    97         this->assertNoSetContext(fPaint);
    98     }
    99     ~AutoCheckNoSetContext() {
   100         this->assertNoSetContext(fPaint);
   101     }
   103 private:
   104     const SkPaint& fPaint;
   106     void assertNoSetContext(const SkPaint& paint) {
   107         SkShader* s = paint.getShader();
   108         if (s) {
   109             SkASSERT(!s->setContextHasBeenCalled());
   110         }
   111     }
   112 };
   114 #define CHECK_LOCKCOUNT_BALANCE(bitmap)  AutoCheckLockCountBalance clcb(bitmap)
   115 #define CHECK_SHADER_NOSETCONTEXT(paint) AutoCheckNoSetContext     cshsc(paint)
   117 #else
   118     #define CHECK_LOCKCOUNT_BALANCE(bitmap)
   119     #define CHECK_SHADER_NOSETCONTEXT(paint)
   120 #endif
   122 typedef SkTLazy<SkPaint> SkLazyPaint;
   124 void SkCanvas::predrawNotify() {
   125     if (fSurfaceBase) {
   126         fSurfaceBase->aboutToDraw(SkSurface::kRetain_ContentChangeMode);
   127     }
   128 }
   130 ///////////////////////////////////////////////////////////////////////////////
   132 /*  This is the record we keep for each SkBaseDevice that the user installs.
   133     The clip/matrix/proc are fields that reflect the top of the save/restore
   134     stack. Whenever the canvas changes, it marks a dirty flag, and then before
   135     these are used (assuming we're not on a layer) we rebuild these cache
   136     values: they reflect the top of the save stack, but translated and clipped
   137     by the device's XY offset and bitmap-bounds.
   138 */
   139 struct DeviceCM {
   140     DeviceCM*           fNext;
   141     SkBaseDevice*       fDevice;
   142     SkRasterClip        fClip;
   143     const SkMatrix*     fMatrix;
   144     SkPaint*            fPaint; // may be null (in the future)
   146     DeviceCM(SkBaseDevice* device, int x, int y, const SkPaint* paint, SkCanvas* canvas)
   147             : fNext(NULL) {
   148         if (NULL != device) {
   149             device->ref();
   150             device->onAttachToCanvas(canvas);
   151         }
   152         fDevice = device;
   153         fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL;
   154     }
   156     ~DeviceCM() {
   157         if (NULL != fDevice) {
   158             fDevice->onDetachFromCanvas();
   159             fDevice->unref();
   160         }
   161         SkDELETE(fPaint);
   162     }
   164     void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
   165                   const SkClipStack& clipStack, SkRasterClip* updateClip) {
   166         int x = fDevice->getOrigin().x();
   167         int y = fDevice->getOrigin().y();
   168         int width = fDevice->width();
   169         int height = fDevice->height();
   171         if ((x | y) == 0) {
   172             fMatrix = &totalMatrix;
   173             fClip = totalClip;
   174         } else {
   175             fMatrixStorage = totalMatrix;
   176             fMatrixStorage.postTranslate(SkIntToScalar(-x),
   177                                          SkIntToScalar(-y));
   178             fMatrix = &fMatrixStorage;
   180             totalClip.translate(-x, -y, &fClip);
   181         }
   183         fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
   185         // intersect clip, but don't translate it (yet)
   187         if (updateClip) {
   188             updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
   189                            SkRegion::kDifference_Op);
   190         }
   192         fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
   194 #ifdef SK_DEBUG
   195         if (!fClip.isEmpty()) {
   196             SkIRect deviceR;
   197             deviceR.set(0, 0, width, height);
   198             SkASSERT(deviceR.contains(fClip.getBounds()));
   199         }
   200 #endif
   201     }
   203 private:
   204     SkMatrix    fMatrixStorage;
   205 };
   207 /*  This is the record we keep for each save/restore level in the stack.
   208     Since a level optionally copies the matrix and/or stack, we have pointers
   209     for these fields. If the value is copied for this level, the copy is
   210     stored in the ...Storage field, and the pointer points to that. If the
   211     value is not copied for this level, we ignore ...Storage, and just point
   212     at the corresponding value in the previous level in the stack.
   213 */
   214 class SkCanvas::MCRec {
   215 public:
   216     int             fFlags;
   217     SkMatrix*       fMatrix;        // points to either fMatrixStorage or prev MCRec
   218     SkRasterClip*   fRasterClip;    // points to either fRegionStorage or prev MCRec
   219     SkDrawFilter*   fFilter;        // the current filter (or null)
   221     DeviceCM*   fLayer;
   222     /*  If there are any layers in the stack, this points to the top-most
   223         one that is at or below this level in the stack (so we know what
   224         bitmap/device to draw into from this level. This value is NOT
   225         reference counted, since the real owner is either our fLayer field,
   226         or a previous one in a lower level.)
   227     */
   228     DeviceCM*   fTopLayer;
   230     MCRec(const MCRec* prev, int flags) : fFlags(flags) {
   231         if (NULL != prev) {
   232             if (flags & SkCanvas::kMatrix_SaveFlag) {
   233                 fMatrixStorage = *prev->fMatrix;
   234                 fMatrix = &fMatrixStorage;
   235             } else {
   236                 fMatrix = prev->fMatrix;
   237             }
   239             if (flags & SkCanvas::kClip_SaveFlag) {
   240                 fRasterClipStorage = *prev->fRasterClip;
   241                 fRasterClip = &fRasterClipStorage;
   242             } else {
   243                 fRasterClip = prev->fRasterClip;
   244             }
   246             fFilter = prev->fFilter;
   247             SkSafeRef(fFilter);
   249             fTopLayer = prev->fTopLayer;
   250         } else {   // no prev
   251             fMatrixStorage.reset();
   253             fMatrix     = &fMatrixStorage;
   254             fRasterClip = &fRasterClipStorage;
   255             fFilter     = NULL;
   256             fTopLayer   = NULL;
   257         }
   258         fLayer = NULL;
   260         // don't bother initializing fNext
   261         inc_rec();
   262     }
   263     ~MCRec() {
   264         SkSafeUnref(fFilter);
   265         SkDELETE(fLayer);
   266         dec_rec();
   267     }
   269 private:
   270     SkMatrix        fMatrixStorage;
   271     SkRasterClip    fRasterClipStorage;
   272 };
   274 class SkDrawIter : public SkDraw {
   275 public:
   276     SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
   277         canvas = canvas->canvasForDrawIter();
   278         fCanvas = canvas;
   279         canvas->updateDeviceCMCache();
   281         fClipStack = &canvas->fClipStack;
   282         fBounder = canvas->getBounder();
   283         fCurrLayer = canvas->fMCRec->fTopLayer;
   284         fSkipEmptyClips = skipEmptyClips;
   285     }
   287     bool next() {
   288         // skip over recs with empty clips
   289         if (fSkipEmptyClips) {
   290             while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
   291                 fCurrLayer = fCurrLayer->fNext;
   292             }
   293         }
   295         const DeviceCM* rec = fCurrLayer;
   296         if (rec && rec->fDevice) {
   298             fMatrix = rec->fMatrix;
   299             fClip   = &((SkRasterClip*)&rec->fClip)->forceGetBW();
   300             fRC     = &rec->fClip;
   301             fDevice = rec->fDevice;
   302             fBitmap = &fDevice->accessBitmap(true);
   303             fPaint  = rec->fPaint;
   304             SkDEBUGCODE(this->validate();)
   306             fCurrLayer = rec->fNext;
   307             if (fBounder) {
   308                 fBounder->setClip(fClip);
   309             }
   310             // fCurrLayer may be NULL now
   312             return true;
   313         }
   314         return false;
   315     }
   317     SkBaseDevice* getDevice() const { return fDevice; }
   318     int getX() const { return fDevice->getOrigin().x(); }
   319     int getY() const { return fDevice->getOrigin().y(); }
   320     const SkMatrix& getMatrix() const { return *fMatrix; }
   321     const SkRegion& getClip() const { return *fClip; }
   322     const SkPaint* getPaint() const { return fPaint; }
   324 private:
   325     SkCanvas*       fCanvas;
   326     const DeviceCM* fCurrLayer;
   327     const SkPaint*  fPaint;     // May be null.
   328     SkBool8         fSkipEmptyClips;
   330     typedef SkDraw INHERITED;
   331 };
   333 /////////////////////////////////////////////////////////////////////////////
   335 class AutoDrawLooper {
   336 public:
   337     AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint,
   338                    bool skipLayerForImageFilter = false,
   339                    const SkRect* bounds = NULL) : fOrigPaint(paint) {
   340         fCanvas = canvas;
   341         fFilter = canvas->getDrawFilter();
   342         fPaint = NULL;
   343         fSaveCount = canvas->getSaveCount();
   344         fDoClearImageFilter = false;
   345         fDone = false;
   347         if (!skipLayerForImageFilter && fOrigPaint.getImageFilter()) {
   348             SkPaint tmp;
   349             tmp.setImageFilter(fOrigPaint.getImageFilter());
   350             (void)canvas->internalSaveLayer(bounds, &tmp, SkCanvas::kARGB_ClipLayer_SaveFlag,
   351                                             true, SkCanvas::kFullLayer_SaveLayerStrategy);
   352             // we'll clear the imageFilter for the actual draws in next(), so
   353             // it will only be applied during the restore().
   354             fDoClearImageFilter = true;
   355         }
   357         if (SkDrawLooper* looper = paint.getLooper()) {
   358             void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
   359                     looper->contextSize());
   360             fLooperContext = looper->createContext(canvas, buffer);
   361             fIsSimple = false;
   362         } else {
   363             fLooperContext = NULL;
   364             // can we be marked as simple?
   365             fIsSimple = !fFilter && !fDoClearImageFilter;
   366         }
   367     }
   369     ~AutoDrawLooper() {
   370         if (fDoClearImageFilter) {
   371             fCanvas->internalRestore();
   372         }
   373         SkASSERT(fCanvas->getSaveCount() == fSaveCount);
   374     }
   376     const SkPaint& paint() const {
   377         SkASSERT(fPaint);
   378         return *fPaint;
   379     }
   381     bool next(SkDrawFilter::Type drawType) {
   382         if (fDone) {
   383             return false;
   384         } else if (fIsSimple) {
   385             fDone = true;
   386             fPaint = &fOrigPaint;
   387             return !fPaint->nothingToDraw();
   388         } else {
   389             return this->doNext(drawType);
   390         }
   391     }
   393 private:
   394     SkLazyPaint     fLazyPaint;
   395     SkCanvas*       fCanvas;
   396     const SkPaint&  fOrigPaint;
   397     SkDrawFilter*   fFilter;
   398     const SkPaint*  fPaint;
   399     int             fSaveCount;
   400     bool            fDoClearImageFilter;
   401     bool            fDone;
   402     bool            fIsSimple;
   403     SkDrawLooper::Context* fLooperContext;
   404     SkSmallAllocator<1, 32> fLooperContextAllocator;
   406     bool doNext(SkDrawFilter::Type drawType);
   407 };
   409 bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
   410     fPaint = NULL;
   411     SkASSERT(!fIsSimple);
   412     SkASSERT(fLooperContext || fFilter || fDoClearImageFilter);
   414     SkPaint* paint = fLazyPaint.set(fOrigPaint);
   416     if (fDoClearImageFilter) {
   417         paint->setImageFilter(NULL);
   418     }
   420     if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
   421         fDone = true;
   422         return false;
   423     }
   424     if (fFilter) {
   425         if (!fFilter->filter(paint, drawType)) {
   426             fDone = true;
   427             return false;
   428         }
   429         if (NULL == fLooperContext) {
   430             // no looper means we only draw once
   431             fDone = true;
   432         }
   433     }
   434     fPaint = paint;
   436     // if we only came in here for the imagefilter, mark us as done
   437     if (!fLooperContext && !fFilter) {
   438         fDone = true;
   439     }
   441     // call this after any possible paint modifiers
   442     if (fPaint->nothingToDraw()) {
   443         fPaint = NULL;
   444         return false;
   445     }
   446     return true;
   447 }
   449 /*  Stack helper for managing a SkBounder. In the destructor, if we were
   450     given a bounder, we call its commit() method, signifying that we are
   451     done accumulating bounds for that draw.
   452 */
   453 class SkAutoBounderCommit {
   454 public:
   455     SkAutoBounderCommit(SkBounder* bounder) : fBounder(bounder) {}
   456     ~SkAutoBounderCommit() {
   457         if (NULL != fBounder) {
   458             fBounder->commit();
   459         }
   460     }
   461 private:
   462     SkBounder*  fBounder;
   463 };
   464 #define SkAutoBounderCommit(...) SK_REQUIRE_LOCAL_VAR(SkAutoBounderCommit)
   466 #include "SkColorPriv.h"
   468 ////////// macros to place around the internal draw calls //////////////////
   470 #define LOOPER_BEGIN_DRAWDEVICE(paint, type)                        \
   471     this->predrawNotify();                                          \
   472     AutoDrawLooper  looper(this, paint, true);                      \
   473     while (looper.next(type)) {                                     \
   474         SkAutoBounderCommit ac(fBounder);                           \
   475         SkDrawIter          iter(this);
   477 #define LOOPER_BEGIN(paint, type, bounds)                           \
   478     this->predrawNotify();                                          \
   479     AutoDrawLooper  looper(this, paint, false, bounds);             \
   480     while (looper.next(type)) {                                     \
   481         SkAutoBounderCommit ac(fBounder);                           \
   482         SkDrawIter          iter(this);
   484 #define LOOPER_END    }
   486 ////////////////////////////////////////////////////////////////////////////
   488 SkBaseDevice* SkCanvas::init(SkBaseDevice* device) {
   489     fBounder = NULL;
   490     fCachedLocalClipBounds.setEmpty();
   491     fCachedLocalClipBoundsDirty = true;
   492     fAllowSoftClip = true;
   493     fAllowSimplifyClip = false;
   494     fDeviceCMDirty = false;
   495     fSaveLayerCount = 0;
   496     fCullCount = 0;
   497     fMetaData = NULL;
   499     fMCRec = (MCRec*)fMCStack.push_back();
   500     new (fMCRec) MCRec(NULL, 0);
   502     fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL, NULL));
   503     fMCRec->fTopLayer = fMCRec->fLayer;
   505     fSurfaceBase = NULL;
   507     return this->setRootDevice(device);
   508 }
   510 SkCanvas::SkCanvas()
   511     : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
   512 {
   513     inc_canvas();
   515     this->init(NULL);
   516 }
   518 SkCanvas::SkCanvas(int width, int height)
   519     : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
   520 {
   521     inc_canvas();
   523     SkBitmap bitmap;
   524     bitmap.setConfig(SkImageInfo::MakeUnknown(width, height));
   525     this->init(SkNEW_ARGS(SkBitmapDevice, (bitmap)))->unref();
   526 }
   528 SkCanvas::SkCanvas(SkBaseDevice* device)
   529     : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
   530 {
   531     inc_canvas();
   533     this->init(device);
   534 }
   536 SkCanvas::SkCanvas(const SkBitmap& bitmap)
   537     : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
   538 {
   539     inc_canvas();
   541     this->init(SkNEW_ARGS(SkBitmapDevice, (bitmap)))->unref();
   542 }
   544 SkCanvas::~SkCanvas() {
   545     // free up the contents of our deque
   546     this->restoreToCount(1);    // restore everything but the last
   547     SkASSERT(0 == fSaveLayerCount);
   549     this->internalRestore();    // restore the last, since we're going away
   551     SkSafeUnref(fBounder);
   552     SkDELETE(fMetaData);
   554     dec_canvas();
   555 }
   557 SkBounder* SkCanvas::setBounder(SkBounder* bounder) {
   558     SkRefCnt_SafeAssign(fBounder, bounder);
   559     return bounder;
   560 }
   562 SkDrawFilter* SkCanvas::getDrawFilter() const {
   563     return fMCRec->fFilter;
   564 }
   566 SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
   567     SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
   568     return filter;
   569 }
   571 SkMetaData& SkCanvas::getMetaData() {
   572     // metadata users are rare, so we lazily allocate it. If that changes we
   573     // can decide to just make it a field in the device (rather than a ptr)
   574     if (NULL == fMetaData) {
   575         fMetaData = new SkMetaData;
   576     }
   577     return *fMetaData;
   578 }
   580 ///////////////////////////////////////////////////////////////////////////////
   582 void SkCanvas::flush() {
   583     SkBaseDevice* device = this->getDevice();
   584     if (device) {
   585         device->flush();
   586     }
   587 }
   589 SkISize SkCanvas::getTopLayerSize() const {
   590     SkBaseDevice* d = this->getTopDevice();
   591     return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
   592 }
   594 SkIPoint SkCanvas::getTopLayerOrigin() const {
   595     SkBaseDevice* d = this->getTopDevice();
   596     return d ? d->getOrigin() : SkIPoint::Make(0, 0);
   597 }
   599 SkISize SkCanvas::getBaseLayerSize() const {
   600     SkBaseDevice* d = this->getDevice();
   601     return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
   602 }
   604 SkBaseDevice* SkCanvas::getDevice() const {
   605     // return root device
   606     MCRec* rec = (MCRec*) fMCStack.front();
   607     SkASSERT(rec && rec->fLayer);
   608     return rec->fLayer->fDevice;
   609 }
   611 SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
   612     if (updateMatrixClip) {
   613         const_cast<SkCanvas*>(this)->updateDeviceCMCache();
   614     }
   615     return fMCRec->fTopLayer->fDevice;
   616 }
   618 SkBaseDevice* SkCanvas::setRootDevice(SkBaseDevice* device) {
   619     // return root device
   620     SkDeque::F2BIter iter(fMCStack);
   621     MCRec*           rec = (MCRec*)iter.next();
   622     SkASSERT(rec && rec->fLayer);
   623     SkBaseDevice*    rootDevice = rec->fLayer->fDevice;
   625     if (rootDevice == device) {
   626         return device;
   627     }
   629     if (device) {
   630         device->onAttachToCanvas(this);
   631     }
   632     if (rootDevice) {
   633         rootDevice->onDetachFromCanvas();
   634     }
   636     SkRefCnt_SafeAssign(rec->fLayer->fDevice, device);
   637     rootDevice = device;
   639     fDeviceCMDirty = true;
   641     /*  Now we update our initial region to have the bounds of the new device,
   642         and then intersect all of the clips in our stack with these bounds,
   643         to ensure that we can't draw outside of the device's bounds (and trash
   644                                                                      memory).
   646     NOTE: this is only a partial-fix, since if the new device is larger than
   647         the previous one, we don't know how to "enlarge" the clips in our stack,
   648         so drawing may be artificially restricted. Without keeping a history of
   649         all calls to canvas->clipRect() and canvas->clipPath(), we can't exactly
   650         reconstruct the correct clips, so this approximation will have to do.
   651         The caller really needs to restore() back to the base if they want to
   652         accurately take advantage of the new device bounds.
   653     */
   655     SkIRect bounds;
   656     if (device) {
   657         bounds.set(0, 0, device->width(), device->height());
   658     } else {
   659         bounds.setEmpty();
   660     }
   661     // now jam our 1st clip to be bounds, and intersect the rest with that
   662     rec->fRasterClip->setRect(bounds);
   663     while ((rec = (MCRec*)iter.next()) != NULL) {
   664         (void)rec->fRasterClip->op(bounds, SkRegion::kIntersect_Op);
   665     }
   667     return device;
   668 }
   670 bool SkCanvas::readPixels(SkBitmap* bitmap,
   671                           int x, int y,
   672                           Config8888 config8888) {
   673     SkBaseDevice* device = this->getDevice();
   674     if (!device) {
   675         return false;
   676     }
   677     return device->readPixels(bitmap, x, y, config8888);
   678 }
   680 bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
   681     SkBaseDevice* device = this->getDevice();
   682     if (!device) {
   683         return false;
   684     }
   686     SkIRect bounds;
   687     bounds.set(0, 0, device->width(), device->height());
   688     if (!bounds.intersect(srcRect)) {
   689         return false;
   690     }
   692     SkBitmap tmp;
   693     tmp.setConfig(SkBitmap::kARGB_8888_Config, bounds.width(),
   694                                                bounds.height());
   695     if (this->readPixels(&tmp, bounds.fLeft, bounds.fTop)) {
   696         bitmap->swap(tmp);
   697         return true;
   698     } else {
   699         return false;
   700     }
   701 }
   703 #ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
   704 void SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y,
   705                            Config8888 config8888) {
   706     SkBaseDevice* device = this->getDevice();
   707     if (device) {
   708         if (SkIRect::Intersects(SkIRect::MakeSize(this->getDeviceSize()),
   709                                 SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height()))) {
   710             device->accessBitmap(true);
   711             device->writePixels(bitmap, x, y, config8888);
   712         }
   713     }
   714 }
   715 #endif
   717 bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
   718     if (bitmap.getTexture()) {
   719         return false;
   720     }
   721     SkBitmap bm(bitmap);
   722     bm.lockPixels();
   723     if (bm.getPixels()) {
   724         return this->writePixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y);
   725     }
   726     return false;
   727 }
   729 bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
   730                            int x, int y) {
   731     switch (origInfo.colorType()) {
   732         case kUnknown_SkColorType:
   733         case kIndex_8_SkColorType:
   734             return false;
   735         default:
   736             break;
   737     }
   738     if (NULL == pixels || rowBytes < origInfo.minRowBytes()) {
   739         return false;
   740     }
   742     const SkISize size = this->getBaseLayerSize();
   743     SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
   744     if (!target.intersect(0, 0, size.width(), size.height())) {
   745         return false;
   746     }
   748     SkBaseDevice* device = this->getDevice();
   749     if (!device) {
   750         return false;
   751     }
   753     SkImageInfo info = origInfo;
   754     // the intersect may have shrunk info's logical size
   755     info.fWidth = target.width();
   756     info.fHeight = target.height();
   758     // if x or y are negative, then we have to adjust pixels
   759     if (x > 0) {
   760         x = 0;
   761     }
   762     if (y > 0) {
   763         y = 0;
   764     }
   765     // here x,y are either 0 or negative
   766     pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
   768     // The device can assert that the requested area is always contained in its bounds
   769     return device->writePixelsDirect(info, pixels, rowBytes, target.x(), target.y());
   770 }
   772 SkCanvas* SkCanvas::canvasForDrawIter() {
   773     return this;
   774 }
   776 //////////////////////////////////////////////////////////////////////////////
   778 void SkCanvas::updateDeviceCMCache() {
   779     if (fDeviceCMDirty) {
   780         const SkMatrix& totalMatrix = this->getTotalMatrix();
   781         const SkRasterClip& totalClip = *fMCRec->fRasterClip;
   782         DeviceCM*       layer = fMCRec->fTopLayer;
   784         if (NULL == layer->fNext) {   // only one layer
   785             layer->updateMC(totalMatrix, totalClip, fClipStack, NULL);
   786         } else {
   787             SkRasterClip clip(totalClip);
   788             do {
   789                 layer->updateMC(totalMatrix, clip, fClipStack, &clip);
   790             } while ((layer = layer->fNext) != NULL);
   791         }
   792         fDeviceCMDirty = false;
   793     }
   794 }
   796 ///////////////////////////////////////////////////////////////////////////////
   798 int SkCanvas::internalSave(SaveFlags flags) {
   799     int saveCount = this->getSaveCount(); // record this before the actual save
   801     MCRec* newTop = (MCRec*)fMCStack.push_back();
   802     new (newTop) MCRec(fMCRec, flags);    // balanced in restore()
   804     fMCRec = newTop;
   806     if (SkCanvas::kClip_SaveFlag & flags) {
   807         fClipStack.save();
   808     }
   810     return saveCount;
   811 }
   813 void SkCanvas::willSave(SaveFlags) {
   814     // Do nothing. Subclasses may do something.
   815 }
   817 int SkCanvas::save(SaveFlags flags) {
   818     this->willSave(flags);
   819     // call shared impl
   820     return this->internalSave(flags);
   821 }
   823 static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
   824 #ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
   825     return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
   826 #else
   827     return true;
   828 #endif
   829 }
   831 bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
   832                                SkIRect* intersection, const SkImageFilter* imageFilter) {
   833     SkIRect clipBounds;
   834     SkRegion::Op op = SkRegion::kIntersect_Op;
   835     if (!this->getClipDeviceBounds(&clipBounds)) {
   836         return false;
   837     }
   839     if (imageFilter) {
   840         imageFilter->filterBounds(clipBounds, *fMCRec->fMatrix, &clipBounds);
   841         // Filters may grow the bounds beyond the device bounds.
   842         op = SkRegion::kReplace_Op;
   843     }
   844     SkIRect ir;
   845     if (NULL != bounds) {
   846         SkRect r;
   848         this->getTotalMatrix().mapRect(&r, *bounds);
   849         r.roundOut(&ir);
   850         // early exit if the layer's bounds are clipped out
   851         if (!ir.intersect(clipBounds)) {
   852             if (bounds_affects_clip(flags)) {
   853                 fMCRec->fRasterClip->setEmpty();
   854             }
   855             return false;
   856         }
   857     } else {    // no user bounds, so just use the clip
   858         ir = clipBounds;
   859     }
   861     if (bounds_affects_clip(flags)) {
   862         fClipStack.clipDevRect(ir, op);
   863         // early exit if the clip is now empty
   864         if (!fMCRec->fRasterClip->op(ir, op)) {
   865             return false;
   866         }
   867     }
   869     if (intersection) {
   870         *intersection = ir;
   871     }
   872     return true;
   873 }
   875 SkCanvas::SaveLayerStrategy SkCanvas::willSaveLayer(const SkRect*, const SkPaint*, SaveFlags) {
   877     // Do nothing. Subclasses may do something.
   878     return kFullLayer_SaveLayerStrategy;
   879 }
   881 int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
   882                         SaveFlags flags) {
   883     // Overriding classes may return false to signal that we don't need to create a layer.
   884     SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags);
   885     return this->internalSaveLayer(bounds, paint, flags, false, strategy);
   886 }
   888 static SkBaseDevice* createCompatibleDevice(SkCanvas* canvas,
   889                                             const SkImageInfo& info) {
   890     SkBaseDevice* device = canvas->getDevice();
   891     return device ? device->createCompatibleDevice(info) : NULL;
   892 }
   894 int SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags,
   895                                 bool justForImageFilter, SaveLayerStrategy strategy) {
   896 #ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
   897     flags = (SaveFlags)(flags | kClipToLayer_SaveFlag);
   898 #endif
   900     // do this before we create the layer. We don't call the public save() since
   901     // that would invoke a possibly overridden virtual
   902     int count = this->internalSave(flags);
   904     fDeviceCMDirty = true;
   906     SkIRect ir;
   907     if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : NULL)) {
   908         return count;
   909     }
   911     // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
   912     // the clipRectBounds() call above?
   913     if (kNoLayer_SaveLayerStrategy == strategy) {
   914         return count;
   915     }
   917     // Kill the imagefilter if our device doesn't allow it
   918     SkLazyPaint lazyP;
   919     if (paint && paint->getImageFilter()) {
   920         if (!this->getTopDevice()->allowImageFilter(paint->getImageFilter())) {
   921             if (justForImageFilter) {
   922                 // early exit if the layer was just for the imageFilter
   923                 return count;
   924             }
   925             SkPaint* p = lazyP.set(*paint);
   926             p->setImageFilter(NULL);
   927             paint = p;
   928         }
   929     }
   931     bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag);
   932     SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
   933                         isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
   935     SkBaseDevice* device;
   936     if (paint && paint->getImageFilter()) {
   937         device = createCompatibleDevice(this, info);
   938     } else {
   939         device = this->createLayerDevice(info);
   940     }
   941     if (NULL == device) {
   942         SkDebugf("Unable to create device for layer.");
   943         return count;
   944     }
   946     device->setOrigin(ir.fLeft, ir.fTop);
   947     DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint, this));
   948     device->unref();
   950     layer->fNext = fMCRec->fTopLayer;
   951     fMCRec->fLayer = layer;
   952     fMCRec->fTopLayer = layer;    // this field is NOT an owner of layer
   954     fSaveLayerCount += 1;
   955     return count;
   956 }
   958 int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
   959                              SaveFlags flags) {
   960     if (0xFF == alpha) {
   961         return this->saveLayer(bounds, NULL, flags);
   962     } else {
   963         SkPaint tmpPaint;
   964         tmpPaint.setAlpha(alpha);
   965         return this->saveLayer(bounds, &tmpPaint, flags);
   966     }
   967 }
   969 void SkCanvas::willRestore() {
   970     // Do nothing. Subclasses may do something.
   971 }
   973 void SkCanvas::restore() {
   974     // check for underflow
   975     if (fMCStack.count() > 1) {
   976         this->willRestore();
   977         this->internalRestore();
   978     }
   979 }
   981 void SkCanvas::internalRestore() {
   982     SkASSERT(fMCStack.count() != 0);
   984     fDeviceCMDirty = true;
   985     fCachedLocalClipBoundsDirty = true;
   987     if (SkCanvas::kClip_SaveFlag & fMCRec->fFlags) {
   988         fClipStack.restore();
   989     }
   991     // reserve our layer (if any)
   992     DeviceCM* layer = fMCRec->fLayer;   // may be null
   993     // now detach it from fMCRec so we can pop(). Gets freed after its drawn
   994     fMCRec->fLayer = NULL;
   996     // now do the normal restore()
   997     fMCRec->~MCRec();       // balanced in save()
   998     fMCStack.pop_back();
   999     fMCRec = (MCRec*)fMCStack.back();
  1001     /*  Time to draw the layer's offscreen. We can't call the public drawSprite,
  1002         since if we're being recorded, we don't want to record this (the
  1003         recorder will have already recorded the restore).
  1004     */
  1005     if (NULL != layer) {
  1006         if (layer->fNext) {
  1007             const SkIPoint& origin = layer->fDevice->getOrigin();
  1008             this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
  1009                                      layer->fPaint);
  1010             // reset this, since internalDrawDevice will have set it to true
  1011             fDeviceCMDirty = true;
  1013             SkASSERT(fSaveLayerCount > 0);
  1014             fSaveLayerCount -= 1;
  1016         SkDELETE(layer);
  1020 int SkCanvas::getSaveCount() const {
  1021     return fMCStack.count();
  1024 void SkCanvas::restoreToCount(int count) {
  1025     // sanity check
  1026     if (count < 1) {
  1027         count = 1;
  1030     int n = this->getSaveCount() - count;
  1031     for (int i = 0; i < n; ++i) {
  1032         this->restore();
  1036 bool SkCanvas::isDrawingToLayer() const {
  1037     return fSaveLayerCount > 0;
  1040 SkSurface* SkCanvas::newSurface(const SkImageInfo& info) {
  1041     return this->onNewSurface(info);
  1044 SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info) {
  1045     SkBaseDevice* dev = this->getDevice();
  1046     return dev ? dev->newSurface(info) : NULL;
  1049 SkImageInfo SkCanvas::imageInfo() const {
  1050     SkBaseDevice* dev = this->getDevice();
  1051     if (dev) {
  1052         return dev->imageInfo();
  1053     } else {
  1054         return SkImageInfo::MakeUnknown(0, 0);
  1058 const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
  1059     return this->onPeekPixels(info, rowBytes);
  1062 const void* SkCanvas::onPeekPixels(SkImageInfo* info, size_t* rowBytes) {
  1063     SkBaseDevice* dev = this->getDevice();
  1064     return dev ? dev->peekPixels(info, rowBytes) : NULL;
  1067 void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) {
  1068     return this->onAccessTopLayerPixels(info, rowBytes);
  1071 void* SkCanvas::onAccessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) {
  1072     SkBaseDevice* dev = this->getTopDevice();
  1073     return dev ? dev->accessPixels(info, rowBytes) : NULL;
  1076 SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
  1077     fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
  1078     if (NULL == fAddr) {
  1079         fInfo = canvas->imageInfo();
  1080         if (kUnknown_SkColorType == fInfo.colorType() ||
  1081             !fBitmap.allocPixels(fInfo))
  1083             return; // failure, fAddr is NULL
  1085         fBitmap.lockPixels();
  1086         if (!canvas->readPixels(&fBitmap, 0, 0)) {
  1087             return; // failure, fAddr is NULL
  1089         fAddr = fBitmap.getPixels();
  1090         fRowBytes = fBitmap.rowBytes();
  1092     SkASSERT(fAddr);    // success
  1095 bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
  1096     if (fAddr) {
  1097         return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes,
  1098                                      NULL, NULL);
  1099     } else {
  1100         bitmap->reset();
  1101         return false;
  1105 void SkCanvas::onPushCull(const SkRect& cullRect) {
  1106     // do nothing. Subclasses may do something
  1109 void SkCanvas::onPopCull() {
  1110     // do nothing. Subclasses may do something
  1113 /////////////////////////////////////////////////////////////////////////////
  1115 void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap,
  1116                                 const SkMatrix& matrix, const SkPaint* paint) {
  1117     if (bitmap.drawsNothing()) {
  1118         return;
  1121     SkLazyPaint lazy;
  1122     if (NULL == paint) {
  1123         paint = lazy.init();
  1126     SkDEBUGCODE(bitmap.validate();)
  1127     CHECK_LOCKCOUNT_BALANCE(bitmap);
  1129     SkRect storage;
  1130     const SkRect* bounds = NULL;
  1131     if (paint && paint->canComputeFastBounds()) {
  1132         bitmap.getBounds(&storage);
  1133         matrix.mapRect(&storage);
  1134         bounds = &paint->computeFastBounds(storage, &storage);
  1137     LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
  1139     while (iter.next()) {
  1140         iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
  1143     LOOPER_END
  1146 void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
  1147                                   const SkPaint* paint) {
  1148     SkPaint tmp;
  1149     if (NULL == paint) {
  1150         tmp.setDither(true);
  1151         paint = &tmp;
  1154     LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
  1155     while (iter.next()) {
  1156         SkBaseDevice* dstDev = iter.fDevice;
  1157         paint = &looper.paint();
  1158         SkImageFilter* filter = paint->getImageFilter();
  1159         SkIPoint pos = { x - iter.getX(), y - iter.getY() };
  1160         if (filter && !dstDev->canHandleImageFilter(filter)) {
  1161             SkDeviceImageFilterProxy proxy(dstDev);
  1162             SkBitmap dst;
  1163             SkIPoint offset = SkIPoint::Make(0, 0);
  1164             const SkBitmap& src = srcDev->accessBitmap(false);
  1165             SkMatrix matrix = *iter.fMatrix;
  1166             matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y));
  1167             SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
  1168             SkImageFilter::Context ctx(matrix, clipBounds);
  1169             if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
  1170                 SkPaint tmpUnfiltered(*paint);
  1171                 tmpUnfiltered.setImageFilter(NULL);
  1172                 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
  1173                                    tmpUnfiltered);
  1175         } else {
  1176             dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
  1179     LOOPER_END
  1182 void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y,
  1183                           const SkPaint* paint) {
  1184     if (bitmap.drawsNothing()) {
  1185         return;
  1187     SkDEBUGCODE(bitmap.validate();)
  1188     CHECK_LOCKCOUNT_BALANCE(bitmap);
  1190     SkPaint tmp;
  1191     if (NULL == paint) {
  1192         paint = &tmp;
  1195     LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
  1197     while (iter.next()) {
  1198         paint = &looper.paint();
  1199         SkImageFilter* filter = paint->getImageFilter();
  1200         SkIPoint pos = { x - iter.getX(), y - iter.getY() };
  1201         if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
  1202             SkDeviceImageFilterProxy proxy(iter.fDevice);
  1203             SkBitmap dst;
  1204             SkIPoint offset = SkIPoint::Make(0, 0);
  1205             SkMatrix matrix = *iter.fMatrix;
  1206             matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y));
  1207             SkIRect clipBounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
  1208             SkImageFilter::Context ctx(matrix, clipBounds);
  1209             if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) {
  1210                 SkPaint tmpUnfiltered(*paint);
  1211                 tmpUnfiltered.setImageFilter(NULL);
  1212                 iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
  1213                                          tmpUnfiltered);
  1215         } else {
  1216             iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
  1219     LOOPER_END
  1222 /////////////////////////////////////////////////////////////////////////////
  1223 void SkCanvas::didTranslate(SkScalar, SkScalar) {
  1224     // Do nothing. Subclasses may do something.
  1227 bool SkCanvas::translate(SkScalar dx, SkScalar dy) {
  1228     fDeviceCMDirty = true;
  1229     fCachedLocalClipBoundsDirty = true;
  1230     bool res = fMCRec->fMatrix->preTranslate(dx, dy);
  1232     this->didTranslate(dx, dy);
  1233     return res;
  1236 void SkCanvas::didScale(SkScalar, SkScalar) {
  1237     // Do nothing. Subclasses may do something.
  1240 bool SkCanvas::scale(SkScalar sx, SkScalar sy) {
  1241     fDeviceCMDirty = true;
  1242     fCachedLocalClipBoundsDirty = true;
  1243     bool res = fMCRec->fMatrix->preScale(sx, sy);
  1245     this->didScale(sx, sy);
  1246     return res;
  1249 void SkCanvas::didRotate(SkScalar) {
  1250     // Do nothing. Subclasses may do something.
  1253 bool SkCanvas::rotate(SkScalar degrees) {
  1254     fDeviceCMDirty = true;
  1255     fCachedLocalClipBoundsDirty = true;
  1256     bool res = fMCRec->fMatrix->preRotate(degrees);
  1258     this->didRotate(degrees);
  1259     return res;
  1262 void SkCanvas::didSkew(SkScalar, SkScalar) {
  1263     // Do nothing. Subclasses may do something.
  1266 bool SkCanvas::skew(SkScalar sx, SkScalar sy) {
  1267     fDeviceCMDirty = true;
  1268     fCachedLocalClipBoundsDirty = true;
  1269     bool res = fMCRec->fMatrix->preSkew(sx, sy);
  1271     this->didSkew(sx, sy);
  1272     return res;
  1275 void SkCanvas::didConcat(const SkMatrix&) {
  1276     // Do nothing. Subclasses may do something.
  1279 bool SkCanvas::concat(const SkMatrix& matrix) {
  1280     fDeviceCMDirty = true;
  1281     fCachedLocalClipBoundsDirty = true;
  1282     bool res = fMCRec->fMatrix->preConcat(matrix);
  1284     this->didConcat(matrix);
  1285     return res;
  1288 void SkCanvas::didSetMatrix(const SkMatrix&) {
  1289     // Do nothing. Subclasses may do something.
  1292 void SkCanvas::setMatrix(const SkMatrix& matrix) {
  1293     fDeviceCMDirty = true;
  1294     fCachedLocalClipBoundsDirty = true;
  1295     *fMCRec->fMatrix = matrix;
  1296     this->didSetMatrix(matrix);
  1299 void SkCanvas::resetMatrix() {
  1300     SkMatrix matrix;
  1302     matrix.reset();
  1303     this->setMatrix(matrix);
  1306 //////////////////////////////////////////////////////////////////////////////
  1308 void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
  1309     ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
  1310     this->onClipRect(rect, op, edgeStyle);
  1313 void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
  1314 #ifdef SK_ENABLE_CLIP_QUICKREJECT
  1315     if (SkRegion::kIntersect_Op == op) {
  1316         if (fMCRec->fRasterClip->isEmpty()) {
  1317             return false;
  1320         if (this->quickReject(rect)) {
  1321             fDeviceCMDirty = true;
  1322             fCachedLocalClipBoundsDirty = true;
  1324             fClipStack.clipEmpty();
  1325             return fMCRec->fRasterClip->setEmpty();
  1328 #endif
  1330     AutoValidateClip avc(this);
  1332     fDeviceCMDirty = true;
  1333     fCachedLocalClipBoundsDirty = true;
  1334     if (!fAllowSoftClip) {
  1335         edgeStyle = kHard_ClipEdgeStyle;
  1338     if (fMCRec->fMatrix->rectStaysRect()) {
  1339         // for these simpler matrices, we can stay a rect even after applying
  1340         // the matrix. This means we don't have to a) make a path, and b) tell
  1341         // the region code to scan-convert the path, only to discover that it
  1342         // is really just a rect.
  1343         SkRect      r;
  1345         fMCRec->fMatrix->mapRect(&r, rect);
  1346         fClipStack.clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle);
  1347         fMCRec->fRasterClip->op(r, op, kSoft_ClipEdgeStyle == edgeStyle);
  1348     } else {
  1349         // since we're rotated or some such thing, we convert the rect to a path
  1350         // and clip against that, since it can handle any matrix. However, to
  1351         // avoid recursion in the case where we are subclassed (e.g. Pictures)
  1352         // we explicitly call "our" version of clipPath.
  1353         SkPath  path;
  1355         path.addRect(rect);
  1356         this->SkCanvas::onClipPath(path, op, edgeStyle);
  1360 static void clip_path_helper(const SkCanvas* canvas, SkRasterClip* currClip,
  1361                              const SkPath& devPath, SkRegion::Op op, bool doAA) {
  1362     // base is used to limit the size (and therefore memory allocation) of the
  1363     // region that results from scan converting devPath.
  1364     SkRegion base;
  1366     if (SkRegion::kIntersect_Op == op) {
  1367         // since we are intersect, we can do better (tighter) with currRgn's
  1368         // bounds, than just using the device. However, if currRgn is complex,
  1369         // our region blitter may hork, so we do that case in two steps.
  1370         if (currClip->isRect()) {
  1371             // FIXME: we should also be able to do this when currClip->isBW(),
  1372             // but relaxing the test above triggers GM asserts in
  1373             // SkRgnBuilder::blitH(). We need to investigate what's going on.
  1374             currClip->setPath(devPath, currClip->bwRgn(), doAA);
  1375         } else {
  1376             base.setRect(currClip->getBounds());
  1377             SkRasterClip clip;
  1378             clip.setPath(devPath, base, doAA);
  1379             currClip->op(clip, op);
  1381     } else {
  1382         const SkBaseDevice* device = canvas->getDevice();
  1383         if (!device) {
  1384             currClip->setEmpty();
  1385             return;
  1388         base.setRect(0, 0, device->width(), device->height());
  1390         if (SkRegion::kReplace_Op == op) {
  1391             currClip->setPath(devPath, base, doAA);
  1392         } else {
  1393             SkRasterClip clip;
  1394             clip.setPath(devPath, base, doAA);
  1395             currClip->op(clip, op);
  1400 void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
  1401     ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
  1402     if (rrect.isRect()) {
  1403         this->onClipRect(rrect.getBounds(), op, edgeStyle);
  1404     } else {
  1405         this->onClipRRect(rrect, op, edgeStyle);
  1409 void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
  1410     SkRRect transformedRRect;
  1411     if (rrect.transform(*fMCRec->fMatrix, &transformedRRect)) {
  1412         AutoValidateClip avc(this);
  1414         fDeviceCMDirty = true;
  1415         fCachedLocalClipBoundsDirty = true;
  1416         if (!fAllowSoftClip) {
  1417             edgeStyle = kHard_ClipEdgeStyle;
  1420         fClipStack.clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
  1422         SkPath devPath;
  1423         devPath.addRRect(transformedRRect);
  1425         clip_path_helper(this, fMCRec->fRasterClip, devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
  1426         return;
  1429     SkPath path;
  1430     path.addRRect(rrect);
  1431     // call the non-virtual version
  1432     this->SkCanvas::onClipPath(path, op, edgeStyle);
  1435 void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
  1436     ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
  1437     SkRect r;
  1438     if (!path.isInverseFillType() && path.isRect(&r)) {
  1439         this->onClipRect(r, op, edgeStyle);
  1440     } else {
  1441         this->onClipPath(path, op, edgeStyle);
  1445 void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
  1446 #ifdef SK_ENABLE_CLIP_QUICKREJECT
  1447     if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
  1448         if (fMCRec->fRasterClip->isEmpty()) {
  1449             return false;
  1452         if (this->quickReject(path.getBounds())) {
  1453             fDeviceCMDirty = true;
  1454             fCachedLocalClipBoundsDirty = true;
  1456             fClipStack.clipEmpty();
  1457             return fMCRec->fRasterClip->setEmpty();
  1460 #endif
  1462     AutoValidateClip avc(this);
  1464     fDeviceCMDirty = true;
  1465     fCachedLocalClipBoundsDirty = true;
  1466     if (!fAllowSoftClip) {
  1467         edgeStyle = kHard_ClipEdgeStyle;
  1470     SkPath devPath;
  1471     path.transform(*fMCRec->fMatrix, &devPath);
  1473     // Check if the transfomation, or the original path itself
  1474     // made us empty. Note this can also happen if we contained NaN
  1475     // values. computing the bounds detects this, and will set our
  1476     // bounds to empty if that is the case. (see SkRect::set(pts, count))
  1477     if (devPath.getBounds().isEmpty()) {
  1478         // resetting the path will remove any NaN or other wanky values
  1479         // that might upset our scan converter.
  1480         devPath.reset();
  1483     // if we called path.swap() we could avoid a deep copy of this path
  1484     fClipStack.clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
  1486     if (fAllowSimplifyClip) {
  1487         devPath.reset();
  1488         devPath.setFillType(SkPath::kInverseEvenOdd_FillType);
  1489         const SkClipStack* clipStack = getClipStack();
  1490         SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterStart);
  1491         const SkClipStack::Element* element;
  1492         while ((element = iter.next())) {
  1493             SkClipStack::Element::Type type = element->getType();
  1494             if (type == SkClipStack::Element::kEmpty_Type) {
  1495                 continue;
  1497             SkPath operand;
  1498             element->asPath(&operand);
  1499             SkRegion::Op elementOp = element->getOp();
  1500             if (elementOp == SkRegion::kReplace_Op) {
  1501                 devPath = operand;
  1502             } else {
  1503                 Op(devPath, operand, (SkPathOp) elementOp, &devPath);
  1505             // if the prev and curr clips disagree about aa -vs- not, favor the aa request.
  1506             // perhaps we need an API change to avoid this sort of mixed-signals about
  1507             // clipping.
  1508             if (element->isAA()) {
  1509                 edgeStyle = kSoft_ClipEdgeStyle;
  1512         op = SkRegion::kReplace_Op;
  1515     clip_path_helper(this, fMCRec->fRasterClip, devPath, op, edgeStyle);
  1518 void SkCanvas::updateClipConservativelyUsingBounds(const SkRect& bounds, SkRegion::Op op,
  1519                                                    bool inverseFilled) {
  1520     // This is for updating the clip conservatively using only bounds
  1521     // information.
  1522     // Contract:
  1523     //    The current clip must contain the true clip. The true
  1524     //    clip is the clip that would have normally been computed
  1525     //    by calls to clipPath and clipRRect
  1526     // Objective:
  1527     //    Keep the current clip as small as possible without
  1528     //    breaking the contract, using only clip bounding rectangles
  1529     //    (for performance).
  1531     // N.B.: This *never* calls back through a virtual on canvas, so subclasses
  1532     // don't have to worry about getting caught in a loop. Thus anywhere
  1533     // we call a virtual method, we explicitly prefix it with
  1534     // SkCanvas:: to be sure to call the base-class.
  1536     if (inverseFilled) {
  1537         switch (op) {
  1538             case SkRegion::kIntersect_Op:
  1539             case SkRegion::kDifference_Op:
  1540                 // These ops can only shrink the current clip. So leaving
  1541                 // the clip unchanged conservatively respects the contract.
  1542                 break;
  1543             case SkRegion::kUnion_Op:
  1544             case SkRegion::kReplace_Op:
  1545             case SkRegion::kReverseDifference_Op:
  1546             case SkRegion::kXOR_Op: {
  1547                     // These ops can grow the current clip up to the extents of
  1548                     // the input clip, which is inverse filled, so we just set
  1549                     // the current clip to the device bounds.
  1550                     SkRect deviceBounds;
  1551                     SkIRect deviceIBounds;
  1552                     this->getDevice()->getGlobalBounds(&deviceIBounds);
  1553                     deviceBounds = SkRect::Make(deviceIBounds);
  1554                     this->SkCanvas::save(SkCanvas::kMatrix_SaveFlag);
  1555                     // set the clip in device space
  1556                     this->SkCanvas::setMatrix(SkMatrix::I());
  1557                     this->SkCanvas::onClipRect(deviceBounds, SkRegion::kReplace_Op,
  1558                                                kHard_ClipEdgeStyle);
  1559                     this->SkCanvas::restore(); //pop the matrix, but keep the clip
  1560                     break;
  1562             default:
  1563                 SkASSERT(0); // unhandled op?
  1565     } else {
  1566         // Not inverse filled
  1567         switch (op) {
  1568             case SkRegion::kIntersect_Op:
  1569             case SkRegion::kUnion_Op:
  1570             case SkRegion::kReplace_Op:
  1571                 this->SkCanvas::onClipRect(bounds, op, kHard_ClipEdgeStyle);
  1572                 break;
  1573             case SkRegion::kDifference_Op:
  1574                 // Difference can only shrink the current clip.
  1575                 // Leaving clip unchanged conservatively fullfills the contract.
  1576                 break;
  1577             case SkRegion::kReverseDifference_Op:
  1578                 // To reverse, we swap in the bounds with a replace op.
  1579                 // As with difference, leave it unchanged.
  1580                 this->SkCanvas::onClipRect(bounds, SkRegion::kReplace_Op, kHard_ClipEdgeStyle);
  1581                 break;
  1582             case SkRegion::kXOR_Op:
  1583                 // Be conservative, based on (A XOR B) always included in (A union B),
  1584                 // which is always included in (bounds(A) union bounds(B))
  1585                 this->SkCanvas::onClipRect(bounds, SkRegion::kUnion_Op, kHard_ClipEdgeStyle);
  1586                 break;
  1587             default:
  1588                 SkASSERT(0); // unhandled op?
  1593 void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
  1594     this->onClipRegion(rgn, op);
  1597 void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
  1598     AutoValidateClip avc(this);
  1600     fDeviceCMDirty = true;
  1601     fCachedLocalClipBoundsDirty = true;
  1603     // todo: signal fClipStack that we have a region, and therefore (I guess)
  1604     // we have to ignore it, and use the region directly?
  1605     fClipStack.clipDevRect(rgn.getBounds(), op);
  1607     fMCRec->fRasterClip->op(rgn, op);
  1610 #ifdef SK_DEBUG
  1611 void SkCanvas::validateClip() const {
  1612     // construct clipRgn from the clipstack
  1613     const SkBaseDevice* device = this->getDevice();
  1614     if (!device) {
  1615         SkASSERT(this->isClipEmpty());
  1616         return;
  1619     SkIRect ir;
  1620     ir.set(0, 0, device->width(), device->height());
  1621     SkRasterClip tmpClip(ir);
  1623     SkClipStack::B2TIter                iter(fClipStack);
  1624     const SkClipStack::Element* element;
  1625     while ((element = iter.next()) != NULL) {
  1626         switch (element->getType()) {
  1627             case SkClipStack::Element::kRect_Type:
  1628                 element->getRect().round(&ir);
  1629                 tmpClip.op(ir, element->getOp());
  1630                 break;
  1631             case SkClipStack::Element::kEmpty_Type:
  1632                 tmpClip.setEmpty();
  1633                 break;
  1634             default: {
  1635                 SkPath path;
  1636                 element->asPath(&path);
  1637                 clip_path_helper(this, &tmpClip, path, element->getOp(), element->isAA());
  1638                 break;
  1643 #endif
  1645 void SkCanvas::replayClips(ClipVisitor* visitor) const {
  1646     SkClipStack::B2TIter                iter(fClipStack);
  1647     const SkClipStack::Element*         element;
  1649     static const SkRect kEmpty = { 0, 0, 0, 0 };
  1650     while ((element = iter.next()) != NULL) {
  1651         switch (element->getType()) {
  1652             case SkClipStack::Element::kPath_Type:
  1653                 visitor->clipPath(element->getPath(), element->getOp(), element->isAA());
  1654                 break;
  1655             case SkClipStack::Element::kRRect_Type:
  1656                 visitor->clipRRect(element->getRRect(), element->getOp(), element->isAA());
  1657                 break;
  1658             case SkClipStack::Element::kRect_Type:
  1659                 visitor->clipRect(element->getRect(), element->getOp(), element->isAA());
  1660                 break;
  1661             case SkClipStack::Element::kEmpty_Type:
  1662                 visitor->clipRect(kEmpty, SkRegion::kIntersect_Op, false);
  1663                 break;
  1668 ///////////////////////////////////////////////////////////////////////////////
  1670 bool SkCanvas::isClipEmpty() const {
  1671     return fMCRec->fRasterClip->isEmpty();
  1674 bool SkCanvas::isClipRect() const {
  1675     return fMCRec->fRasterClip->isRect();
  1678 bool SkCanvas::quickReject(const SkRect& rect) const {
  1680     if (!rect.isFinite())
  1681         return true;
  1683     if (fMCRec->fRasterClip->isEmpty()) {
  1684         return true;
  1687     if (fMCRec->fMatrix->hasPerspective()) {
  1688         SkRect dst;
  1689         fMCRec->fMatrix->mapRect(&dst, rect);
  1690         SkIRect idst;
  1691         dst.roundOut(&idst);
  1692         return !SkIRect::Intersects(idst, fMCRec->fRasterClip->getBounds());
  1693     } else {
  1694         const SkRect& clipR = this->getLocalClipBounds();
  1696         // for speed, do the most likely reject compares first
  1697         // TODO: should we use | instead, or compare all 4 at once?
  1698         if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
  1699             return true;
  1701         if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
  1702             return true;
  1704         return false;
  1708 bool SkCanvas::quickReject(const SkPath& path) const {
  1709     return path.isEmpty() || this->quickReject(path.getBounds());
  1712 bool SkCanvas::getClipBounds(SkRect* bounds) const {
  1713     SkIRect ibounds;
  1714     if (!this->getClipDeviceBounds(&ibounds)) {
  1715         return false;
  1718     SkMatrix inverse;
  1719     // if we can't invert the CTM, we can't return local clip bounds
  1720     if (!fMCRec->fMatrix->invert(&inverse)) {
  1721         if (bounds) {
  1722             bounds->setEmpty();
  1724         return false;
  1727     if (NULL != bounds) {
  1728         SkRect r;
  1729         // adjust it outwards in case we are antialiasing
  1730         const int inset = 1;
  1732         r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
  1733                ibounds.fRight + inset, ibounds.fBottom + inset);
  1734         inverse.mapRect(bounds, r);
  1736     return true;
  1739 bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
  1740     const SkRasterClip& clip = *fMCRec->fRasterClip;
  1741     if (clip.isEmpty()) {
  1742         if (bounds) {
  1743             bounds->setEmpty();
  1745         return false;
  1748     if (NULL != bounds) {
  1749         *bounds = clip.getBounds();
  1751     return true;
  1754 const SkMatrix& SkCanvas::getTotalMatrix() const {
  1755     return *fMCRec->fMatrix;
  1758 #ifdef SK_SUPPORT_LEGACY_GETCLIPTYPE
  1759 SkCanvas::ClipType SkCanvas::getClipType() const {
  1760     if (fMCRec->fRasterClip->isEmpty()) {
  1761         return kEmpty_ClipType;
  1763     if (fMCRec->fRasterClip->isRect()) {
  1764         return kRect_ClipType;
  1766     return kComplex_ClipType;
  1768 #endif
  1770 #ifdef SK_SUPPORT_LEGACY_GETTOTALCLIP
  1771 const SkRegion& SkCanvas::getTotalClip() const {
  1772     return fMCRec->fRasterClip->forceGetBW();
  1774 #endif
  1776 const SkRegion& SkCanvas::internal_private_getTotalClip() const {
  1777     return fMCRec->fRasterClip->forceGetBW();
  1780 void SkCanvas::internal_private_getTotalClipAsPath(SkPath* path) const {
  1781     path->reset();
  1783     const SkRegion& rgn = fMCRec->fRasterClip->forceGetBW();
  1784     if (rgn.isEmpty()) {
  1785         return;
  1787     (void)rgn.getBoundaryPath(path);
  1790 GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
  1791     SkBaseDevice* dev = this->getTopDevice();
  1792     return dev ? dev->accessRenderTarget() : NULL;
  1795 SkBaseDevice* SkCanvas::createLayerDevice(const SkImageInfo& info) {
  1796     SkBaseDevice* device = this->getTopDevice();
  1797     return device ? device->createCompatibleDeviceForSaveLayer(info) : NULL;
  1800 GrContext* SkCanvas::getGrContext() {
  1801 #if SK_SUPPORT_GPU
  1802     SkBaseDevice* device = this->getTopDevice();
  1803     if (NULL != device) {
  1804         GrRenderTarget* renderTarget = device->accessRenderTarget();
  1805         if (NULL != renderTarget) {
  1806             return renderTarget->getContext();
  1809 #endif
  1811     return NULL;
  1815 void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
  1816                           const SkPaint& paint) {
  1817     if (outer.isEmpty()) {
  1818         return;
  1820     if (inner.isEmpty()) {
  1821         this->drawRRect(outer, paint);
  1822         return;
  1825     // We don't have this method (yet), but technically this is what we should
  1826     // be able to assert...
  1827     // SkASSERT(outer.contains(inner));
  1828     //
  1829     // For now at least check for containment of bounds
  1830     SkASSERT(outer.getBounds().contains(inner.getBounds()));
  1832     this->onDrawDRRect(outer, inner, paint);
  1835 //////////////////////////////////////////////////////////////////////////////
  1836 //  These are the virtual drawing methods
  1837 //////////////////////////////////////////////////////////////////////////////
  1839 void SkCanvas::clear(SkColor color) {
  1840     SkDrawIter  iter(this);
  1841     this->predrawNotify();
  1842     while (iter.next()) {
  1843         iter.fDevice->clear(color);
  1847 void SkCanvas::drawPaint(const SkPaint& paint) {
  1848     this->internalDrawPaint(paint);
  1851 void SkCanvas::internalDrawPaint(const SkPaint& paint) {
  1852     CHECK_SHADER_NOSETCONTEXT(paint);
  1854     LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL)
  1856     while (iter.next()) {
  1857         iter.fDevice->drawPaint(iter, looper.paint());
  1860     LOOPER_END
  1863 void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
  1864                           const SkPaint& paint) {
  1865     if ((long)count <= 0) {
  1866         return;
  1869     CHECK_SHADER_NOSETCONTEXT(paint);
  1871     SkRect r, storage;
  1872     const SkRect* bounds = NULL;
  1873     if (paint.canComputeFastBounds()) {
  1874         // special-case 2 points (common for drawing a single line)
  1875         if (2 == count) {
  1876             r.set(pts[0], pts[1]);
  1877         } else {
  1878             r.set(pts, SkToInt(count));
  1880         bounds = &paint.computeFastStrokeBounds(r, &storage);
  1881         if (this->quickReject(*bounds)) {
  1882             return;
  1886     SkASSERT(pts != NULL);
  1888     LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
  1890     while (iter.next()) {
  1891         iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
  1894     LOOPER_END
  1897 void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
  1898     CHECK_SHADER_NOSETCONTEXT(paint);
  1900     SkRect storage;
  1901     const SkRect* bounds = NULL;
  1902     if (paint.canComputeFastBounds()) {
  1903         bounds = &paint.computeFastBounds(r, &storage);
  1904         if (this->quickReject(*bounds)) {
  1905             return;
  1909     LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
  1911     while (iter.next()) {
  1912         iter.fDevice->drawRect(iter, r, looper.paint());
  1915     LOOPER_END
  1918 void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
  1919     CHECK_SHADER_NOSETCONTEXT(paint);
  1921     SkRect storage;
  1922     const SkRect* bounds = NULL;
  1923     if (paint.canComputeFastBounds()) {
  1924         bounds = &paint.computeFastBounds(oval, &storage);
  1925         if (this->quickReject(*bounds)) {
  1926             return;
  1930     LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
  1932     while (iter.next()) {
  1933         iter.fDevice->drawOval(iter, oval, looper.paint());
  1936     LOOPER_END
  1939 void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
  1940     CHECK_SHADER_NOSETCONTEXT(paint);
  1942     SkRect storage;
  1943     const SkRect* bounds = NULL;
  1944     if (paint.canComputeFastBounds()) {
  1945         bounds = &paint.computeFastBounds(rrect.getBounds(), &storage);
  1946         if (this->quickReject(*bounds)) {
  1947             return;
  1951     if (rrect.isRect()) {
  1952         // call the non-virtual version
  1953         this->SkCanvas::drawRect(rrect.getBounds(), paint);
  1954         return;
  1955     } else if (rrect.isOval()) {
  1956         // call the non-virtual version
  1957         this->SkCanvas::drawOval(rrect.getBounds(), paint);
  1958         return;
  1961     LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
  1963     while (iter.next()) {
  1964         iter.fDevice->drawRRect(iter, rrect, looper.paint());
  1967     LOOPER_END
  1970 void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
  1971                             const SkPaint& paint) {
  1972     CHECK_SHADER_NOSETCONTEXT(paint);
  1974     SkRect storage;
  1975     const SkRect* bounds = NULL;
  1976     if (paint.canComputeFastBounds()) {
  1977         bounds = &paint.computeFastBounds(outer.getBounds(), &storage);
  1978         if (this->quickReject(*bounds)) {
  1979             return;
  1983     LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
  1985     while (iter.next()) {
  1986         iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
  1989     LOOPER_END
  1992 void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
  1993     CHECK_SHADER_NOSETCONTEXT(paint);
  1995     if (!path.isFinite()) {
  1996         return;
  1999     SkRect storage;
  2000     const SkRect* bounds = NULL;
  2001     if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
  2002         const SkRect& pathBounds = path.getBounds();
  2003         bounds = &paint.computeFastBounds(pathBounds, &storage);
  2004         if (this->quickReject(*bounds)) {
  2005             return;
  2009     const SkRect& r = path.getBounds();
  2010     if (r.width() <= 0 && r.height() <= 0) {
  2011         if (path.isInverseFillType()) {
  2012             this->internalDrawPaint(paint);
  2014         return;
  2017     LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
  2019     while (iter.next()) {
  2020         iter.fDevice->drawPath(iter, path, looper.paint());
  2023     LOOPER_END
  2026 void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
  2027                           const SkPaint* paint) {
  2028     SkDEBUGCODE(bitmap.validate();)
  2030     if (NULL == paint || paint->canComputeFastBounds()) {
  2031         SkRect bounds = {
  2032             x, y,
  2033             x + SkIntToScalar(bitmap.width()),
  2034             y + SkIntToScalar(bitmap.height())
  2035         };
  2036         if (paint) {
  2037             (void)paint->computeFastBounds(bounds, &bounds);
  2039         if (this->quickReject(bounds)) {
  2040             return;
  2044     SkMatrix matrix;
  2045     matrix.setTranslate(x, y);
  2046     this->internalDrawBitmap(bitmap, matrix, paint);
  2049 // this one is non-virtual, so it can be called safely by other canvas apis
  2050 void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
  2051                                       const SkRect& dst, const SkPaint* paint,
  2052                                       DrawBitmapRectFlags flags) {
  2053     if (bitmap.drawsNothing() || dst.isEmpty()) {
  2054         return;
  2057     CHECK_LOCKCOUNT_BALANCE(bitmap);
  2059     SkRect storage;
  2060     const SkRect* bounds = &dst;
  2061     if (NULL == paint || paint->canComputeFastBounds()) {
  2062         if (paint) {
  2063             bounds = &paint->computeFastBounds(dst, &storage);
  2065         if (this->quickReject(*bounds)) {
  2066             return;
  2070     SkLazyPaint lazy;
  2071     if (NULL == paint) {
  2072         paint = lazy.init();
  2075     LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
  2077     while (iter.next()) {
  2078         iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags);
  2081     LOOPER_END
  2084 void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
  2085                                     const SkRect& dst, const SkPaint* paint,
  2086                                     DrawBitmapRectFlags flags) {
  2087     SkDEBUGCODE(bitmap.validate();)
  2088     this->internalDrawBitmapRect(bitmap, src, dst, paint, flags);
  2091 void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
  2092                                 const SkPaint* paint) {
  2093     SkDEBUGCODE(bitmap.validate();)
  2094     this->internalDrawBitmap(bitmap, matrix, paint);
  2097 void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
  2098                                       const SkIRect& center, const SkRect& dst,
  2099                                       const SkPaint* paint) {
  2100     if (bitmap.drawsNothing()) {
  2101         return;
  2103     if (NULL == paint || paint->canComputeFastBounds()) {
  2104         SkRect storage;
  2105         const SkRect* bounds = &dst;
  2106         if (paint) {
  2107             bounds = &paint->computeFastBounds(dst, &storage);
  2109         if (this->quickReject(*bounds)) {
  2110             return;
  2114     const int32_t w = bitmap.width();
  2115     const int32_t h = bitmap.height();
  2117     SkIRect c = center;
  2118     // pin center to the bounds of the bitmap
  2119     c.fLeft = SkMax32(0, center.fLeft);
  2120     c.fTop = SkMax32(0, center.fTop);
  2121     c.fRight = SkPin32(center.fRight, c.fLeft, w);
  2122     c.fBottom = SkPin32(center.fBottom, c.fTop, h);
  2124     const SkScalar srcX[4] = {
  2125         0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w)
  2126     };
  2127     const SkScalar srcY[4] = {
  2128         0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h)
  2129     };
  2130     SkScalar dstX[4] = {
  2131         dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
  2132         dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
  2133     };
  2134     SkScalar dstY[4] = {
  2135         dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
  2136         dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
  2137     };
  2139     if (dstX[1] > dstX[2]) {
  2140         dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
  2141         dstX[2] = dstX[1];
  2144     if (dstY[1] > dstY[2]) {
  2145         dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
  2146         dstY[2] = dstY[1];
  2149     for (int y = 0; y < 3; y++) {
  2150         SkRect s, d;
  2152         s.fTop = srcY[y];
  2153         s.fBottom = srcY[y+1];
  2154         d.fTop = dstY[y];
  2155         d.fBottom = dstY[y+1];
  2156         for (int x = 0; x < 3; x++) {
  2157             s.fLeft = srcX[x];
  2158             s.fRight = srcX[x+1];
  2159             d.fLeft = dstX[x];
  2160             d.fRight = dstX[x+1];
  2161             this->internalDrawBitmapRect(bitmap, &s, d, paint,
  2162                                          kNone_DrawBitmapRectFlag);
  2167 void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
  2168                               const SkRect& dst, const SkPaint* paint) {
  2169     SkDEBUGCODE(bitmap.validate();)
  2171     // Need a device entry-point, so gpu can use a mesh
  2172     this->internalDrawBitmapNine(bitmap, center, dst, paint);
  2175 class SkDeviceFilteredPaint {
  2176 public:
  2177     SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
  2178         SkBaseDevice::TextFlags flags;
  2179         if (device->filterTextFlags(paint, &flags)) {
  2180             SkPaint* newPaint = fLazy.set(paint);
  2181             newPaint->setFlags(flags.fFlags);
  2182             newPaint->setHinting(flags.fHinting);
  2183             fPaint = newPaint;
  2184         } else {
  2185             fPaint = &paint;
  2189     const SkPaint& paint() const { return *fPaint; }
  2191 private:
  2192     const SkPaint*  fPaint;
  2193     SkLazyPaint     fLazy;
  2194 };
  2196 void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
  2197                         const SkRect& r, SkScalar textSize) {
  2198     if (paint.getStyle() == SkPaint::kFill_Style) {
  2199         draw.fDevice->drawRect(draw, r, paint);
  2200     } else {
  2201         SkPaint p(paint);
  2202         p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
  2203         draw.fDevice->drawRect(draw, r, p);
  2207 void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
  2208                                    const char text[], size_t byteLength,
  2209                                    SkScalar x, SkScalar y) {
  2210     SkASSERT(byteLength == 0 || text != NULL);
  2212     // nothing to draw
  2213     if (text == NULL || byteLength == 0 ||
  2214         draw.fClip->isEmpty() ||
  2215         (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
  2216         return;
  2219     SkScalar    width = 0;
  2220     SkPoint     start;
  2222     start.set(0, 0);    // to avoid warning
  2223     if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
  2224                             SkPaint::kStrikeThruText_Flag)) {
  2225         width = paint.measureText(text, byteLength);
  2227         SkScalar offsetX = 0;
  2228         if (paint.getTextAlign() == SkPaint::kCenter_Align) {
  2229             offsetX = SkScalarHalf(width);
  2230         } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
  2231             offsetX = width;
  2233         start.set(x - offsetX, y);
  2236     if (0 == width) {
  2237         return;
  2240     uint32_t flags = paint.getFlags();
  2242     if (flags & (SkPaint::kUnderlineText_Flag |
  2243                  SkPaint::kStrikeThruText_Flag)) {
  2244         SkScalar textSize = paint.getTextSize();
  2245         SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
  2246         SkRect   r;
  2248         r.fLeft = start.fX;
  2249         r.fRight = start.fX + width;
  2251         if (flags & SkPaint::kUnderlineText_Flag) {
  2252             SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
  2253                                              start.fY);
  2254             r.fTop = offset;
  2255             r.fBottom = offset + height;
  2256             DrawRect(draw, paint, r, textSize);
  2258         if (flags & SkPaint::kStrikeThruText_Flag) {
  2259             SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
  2260                                              start.fY);
  2261             r.fTop = offset;
  2262             r.fBottom = offset + height;
  2263             DrawRect(draw, paint, r, textSize);
  2268 void SkCanvas::drawText(const void* text, size_t byteLength,
  2269                         SkScalar x, SkScalar y, const SkPaint& paint) {
  2270     CHECK_SHADER_NOSETCONTEXT(paint);
  2272     LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
  2274     while (iter.next()) {
  2275         SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
  2276         iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
  2277         DrawTextDecorations(iter, dfp.paint(),
  2278                             static_cast<const char*>(text), byteLength, x, y);
  2281     LOOPER_END
  2284 void SkCanvas::drawPosText(const void* text, size_t byteLength,
  2285                            const SkPoint pos[], const SkPaint& paint) {
  2286     CHECK_SHADER_NOSETCONTEXT(paint);
  2288     LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
  2290     while (iter.next()) {
  2291         SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
  2292         iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2,
  2293                                   dfp.paint());
  2296     LOOPER_END
  2299 void SkCanvas::drawPosTextH(const void* text, size_t byteLength,
  2300                             const SkScalar xpos[], SkScalar constY,
  2301                             const SkPaint& paint) {
  2302     CHECK_SHADER_NOSETCONTEXT(paint);
  2304     LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
  2306     while (iter.next()) {
  2307         SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
  2308         iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1,
  2309                                   dfp.paint());
  2312     LOOPER_END
  2315 void SkCanvas::drawTextOnPath(const void* text, size_t byteLength,
  2316                               const SkPath& path, const SkMatrix* matrix,
  2317                               const SkPaint& paint) {
  2318     CHECK_SHADER_NOSETCONTEXT(paint);
  2320     LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
  2322     while (iter.next()) {
  2323         iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
  2324                                      matrix, looper.paint());
  2327     LOOPER_END
  2330 void SkCanvas::drawVertices(VertexMode vmode, int vertexCount,
  2331                             const SkPoint verts[], const SkPoint texs[],
  2332                             const SkColor colors[], SkXfermode* xmode,
  2333                             const uint16_t indices[], int indexCount,
  2334                             const SkPaint& paint) {
  2335     CHECK_SHADER_NOSETCONTEXT(paint);
  2337     LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
  2339     while (iter.next()) {
  2340         iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
  2341                                    colors, xmode, indices, indexCount,
  2342                                    looper.paint());
  2345     LOOPER_END
  2348 //////////////////////////////////////////////////////////////////////////////
  2349 // These methods are NOT virtual, and therefore must call back into virtual
  2350 // methods, rather than actually drawing themselves.
  2351 //////////////////////////////////////////////////////////////////////////////
  2353 void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
  2354                         SkXfermode::Mode mode) {
  2355     SkPaint paint;
  2357     paint.setARGB(a, r, g, b);
  2358     if (SkXfermode::kSrcOver_Mode != mode) {
  2359         paint.setXfermodeMode(mode);
  2361     this->drawPaint(paint);
  2364 void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
  2365     SkPaint paint;
  2367     paint.setColor(c);
  2368     if (SkXfermode::kSrcOver_Mode != mode) {
  2369         paint.setXfermodeMode(mode);
  2371     this->drawPaint(paint);
  2374 void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
  2375     SkPoint pt;
  2377     pt.set(x, y);
  2378     this->drawPoints(kPoints_PointMode, 1, &pt, paint);
  2381 void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
  2382     SkPoint pt;
  2383     SkPaint paint;
  2385     pt.set(x, y);
  2386     paint.setColor(color);
  2387     this->drawPoints(kPoints_PointMode, 1, &pt, paint);
  2390 void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
  2391                         const SkPaint& paint) {
  2392     SkPoint pts[2];
  2394     pts[0].set(x0, y0);
  2395     pts[1].set(x1, y1);
  2396     this->drawPoints(kLines_PointMode, 2, pts, paint);
  2399 void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
  2400                               SkScalar right, SkScalar bottom,
  2401                               const SkPaint& paint) {
  2402     SkRect  r;
  2404     r.set(left, top, right, bottom);
  2405     this->drawRect(r, paint);
  2408 void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
  2409                           const SkPaint& paint) {
  2410     if (radius < 0) {
  2411         radius = 0;
  2414     SkRect  r;
  2415     r.set(cx - radius, cy - radius, cx + radius, cy + radius);
  2416     this->drawOval(r, paint);
  2419 void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
  2420                              const SkPaint& paint) {
  2421     if (rx > 0 && ry > 0) {
  2422         if (paint.canComputeFastBounds()) {
  2423             SkRect storage;
  2424             if (this->quickReject(paint.computeFastBounds(r, &storage))) {
  2425                 return;
  2428         SkRRect rrect;
  2429         rrect.setRectXY(r, rx, ry);
  2430         this->drawRRect(rrect, paint);
  2431     } else {
  2432         this->drawRect(r, paint);
  2436 void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
  2437                        SkScalar sweepAngle, bool useCenter,
  2438                        const SkPaint& paint) {
  2439     if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
  2440         this->drawOval(oval, paint);
  2441     } else {
  2442         SkPath  path;
  2443         if (useCenter) {
  2444             path.moveTo(oval.centerX(), oval.centerY());
  2446         path.arcTo(oval, startAngle, sweepAngle, !useCenter);
  2447         if (useCenter) {
  2448             path.close();
  2450         this->drawPath(path, paint);
  2454 void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
  2455                                 const SkPath& path, SkScalar hOffset,
  2456                                 SkScalar vOffset, const SkPaint& paint) {
  2457     SkMatrix    matrix;
  2459     matrix.setTranslate(hOffset, vOffset);
  2460     this->drawTextOnPath(text, byteLength, path, &matrix, paint);
  2463 ///////////////////////////////////////////////////////////////////////////////
  2464 void SkCanvas::EXPERIMENTAL_optimize(SkPicture* picture) {
  2465     SkBaseDevice* device = this->getDevice();
  2466     if (NULL != device) {
  2467         device->EXPERIMENTAL_optimize(picture);
  2471 void SkCanvas::drawPicture(SkPicture& picture) {
  2472     SkBaseDevice* device = this->getTopDevice();
  2473     if (NULL != device) {
  2474         // Canvas has to first give the device the opportunity to render
  2475         // the picture itself.
  2476         if (device->EXPERIMENTAL_drawPicture(picture)) {
  2477             return; // the device has rendered the entire picture
  2481     picture.draw(this);
  2484 ///////////////////////////////////////////////////////////////////////////////
  2485 ///////////////////////////////////////////////////////////////////////////////
  2487 SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
  2488     SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
  2490     SkASSERT(canvas);
  2492     fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
  2493     fDone = !fImpl->next();
  2496 SkCanvas::LayerIter::~LayerIter() {
  2497     fImpl->~SkDrawIter();
  2500 void SkCanvas::LayerIter::next() {
  2501     fDone = !fImpl->next();
  2504 SkBaseDevice* SkCanvas::LayerIter::device() const {
  2505     return fImpl->getDevice();
  2508 const SkMatrix& SkCanvas::LayerIter::matrix() const {
  2509     return fImpl->getMatrix();
  2512 const SkPaint& SkCanvas::LayerIter::paint() const {
  2513     const SkPaint* paint = fImpl->getPaint();
  2514     if (NULL == paint) {
  2515         paint = &fDefaultPaint;
  2517     return *paint;
  2520 const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
  2521 int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
  2522 int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
  2524 ///////////////////////////////////////////////////////////////////////////////
  2526 SkCanvas::ClipVisitor::~ClipVisitor() { }
  2528 ///////////////////////////////////////////////////////////////////////////////
  2530 static bool supported_for_raster_canvas(const SkImageInfo& info) {
  2531     switch (info.alphaType()) {
  2532         case kPremul_SkAlphaType:
  2533         case kOpaque_SkAlphaType:
  2534             break;
  2535         default:
  2536             return false;
  2539     switch (info.colorType()) {
  2540         case kAlpha_8_SkColorType:
  2541         case kRGB_565_SkColorType:
  2542         case kPMColor_SkColorType:
  2543             break;
  2544         default:
  2545             return false;
  2548     return true;
  2551 SkCanvas* SkCanvas::NewRaster(const SkImageInfo& info) {
  2552     if (!supported_for_raster_canvas(info)) {
  2553         return NULL;
  2556     SkBitmap bitmap;
  2557     if (!bitmap.allocPixels(info)) {
  2558         return NULL;
  2561     // should this functionality be moved into allocPixels()?
  2562     if (!bitmap.info().isOpaque()) {
  2563         bitmap.eraseColor(0);
  2565     return SkNEW_ARGS(SkCanvas, (bitmap));
  2568 SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
  2569     if (!supported_for_raster_canvas(info)) {
  2570         return NULL;
  2573     SkBitmap bitmap;
  2574     if (!bitmap.installPixels(info, pixels, rowBytes)) {
  2575         return NULL;
  2578     // should this functionality be moved into allocPixels()?
  2579     if (!bitmap.info().isOpaque()) {
  2580         bitmap.eraseColor(0);
  2582     return SkNEW_ARGS(SkCanvas, (bitmap));

mercurial