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

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/core/SkCanvas.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,2583 @@
     1.4 +
     1.5 +/*
     1.6 + * Copyright 2008 The Android Open Source Project
     1.7 + *
     1.8 + * Use of this source code is governed by a BSD-style license that can be
     1.9 + * found in the LICENSE file.
    1.10 + */
    1.11 +
    1.12 +
    1.13 +#include "SkCanvas.h"
    1.14 +#include "SkBitmapDevice.h"
    1.15 +#include "SkBounder.h"
    1.16 +#include "SkDeviceImageFilterProxy.h"
    1.17 +#include "SkDraw.h"
    1.18 +#include "SkDrawFilter.h"
    1.19 +#include "SkDrawLooper.h"
    1.20 +#include "SkMetaData.h"
    1.21 +#include "SkPathOps.h"
    1.22 +#include "SkPicture.h"
    1.23 +#include "SkRasterClip.h"
    1.24 +#include "SkRRect.h"
    1.25 +#include "SkSmallAllocator.h"
    1.26 +#include "SkSurface_Base.h"
    1.27 +#include "SkTemplates.h"
    1.28 +#include "SkTextFormatParams.h"
    1.29 +#include "SkTLazy.h"
    1.30 +#include "SkUtils.h"
    1.31 +
    1.32 +#if SK_SUPPORT_GPU
    1.33 +#include "GrRenderTarget.h"
    1.34 +#endif
    1.35 +
    1.36 +// experimental for faster tiled drawing...
    1.37 +//#define SK_ENABLE_CLIP_QUICKREJECT
    1.38 +
    1.39 +//#define SK_TRACE_SAVERESTORE
    1.40 +
    1.41 +#ifdef SK_TRACE_SAVERESTORE
    1.42 +    static int gLayerCounter;
    1.43 +    static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
    1.44 +    static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
    1.45 +
    1.46 +    static int gRecCounter;
    1.47 +    static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
    1.48 +    static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
    1.49 +
    1.50 +    static int gCanvasCounter;
    1.51 +    static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
    1.52 +    static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
    1.53 +#else
    1.54 +    #define inc_layer()
    1.55 +    #define dec_layer()
    1.56 +    #define inc_rec()
    1.57 +    #define dec_rec()
    1.58 +    #define inc_canvas()
    1.59 +    #define dec_canvas()
    1.60 +#endif
    1.61 +
    1.62 +#ifdef SK_DEBUG
    1.63 +#include "SkPixelRef.h"
    1.64 +
    1.65 +/*
    1.66 + *  Some pixelref subclasses can support being "locked" from another thread
    1.67 + *  during the lock-scope of skia calling them. In these instances, this balance
    1.68 + *  check will fail, but may not be indicative of a problem, so we allow a build
    1.69 + *  flag to disable this check.
    1.70 + *
    1.71 + *  Potentially another fix would be to have a (debug-only) virtual or flag on
    1.72 + *  pixelref, which could tell us at runtime if this check is valid. That would
    1.73 + *  eliminate the need for this heavy-handed build check.
    1.74 + */
    1.75 +#ifdef SK_DISABLE_PIXELREF_LOCKCOUNT_BALANCE_CHECK
    1.76 +class AutoCheckLockCountBalance {
    1.77 +public:
    1.78 +    AutoCheckLockCountBalance(const SkBitmap&) { /* do nothing */ }
    1.79 +};
    1.80 +#else
    1.81 +class AutoCheckLockCountBalance {
    1.82 +public:
    1.83 +    AutoCheckLockCountBalance(const SkBitmap& bm) : fPixelRef(bm.pixelRef()) {
    1.84 +        fLockCount = fPixelRef ? fPixelRef->getLockCount() : 0;
    1.85 +    }
    1.86 +    ~AutoCheckLockCountBalance() {
    1.87 +        const int count = fPixelRef ? fPixelRef->getLockCount() : 0;
    1.88 +        SkASSERT(count == fLockCount);
    1.89 +    }
    1.90 +
    1.91 +private:
    1.92 +    const SkPixelRef* fPixelRef;
    1.93 +    int               fLockCount;
    1.94 +};
    1.95 +#endif
    1.96 +
    1.97 +class AutoCheckNoSetContext {
    1.98 +public:
    1.99 +    AutoCheckNoSetContext(const SkPaint& paint) : fPaint(paint) {
   1.100 +        this->assertNoSetContext(fPaint);
   1.101 +    }
   1.102 +    ~AutoCheckNoSetContext() {
   1.103 +        this->assertNoSetContext(fPaint);
   1.104 +    }
   1.105 +
   1.106 +private:
   1.107 +    const SkPaint& fPaint;
   1.108 +
   1.109 +    void assertNoSetContext(const SkPaint& paint) {
   1.110 +        SkShader* s = paint.getShader();
   1.111 +        if (s) {
   1.112 +            SkASSERT(!s->setContextHasBeenCalled());
   1.113 +        }
   1.114 +    }
   1.115 +};
   1.116 +
   1.117 +#define CHECK_LOCKCOUNT_BALANCE(bitmap)  AutoCheckLockCountBalance clcb(bitmap)
   1.118 +#define CHECK_SHADER_NOSETCONTEXT(paint) AutoCheckNoSetContext     cshsc(paint)
   1.119 +
   1.120 +#else
   1.121 +    #define CHECK_LOCKCOUNT_BALANCE(bitmap)
   1.122 +    #define CHECK_SHADER_NOSETCONTEXT(paint)
   1.123 +#endif
   1.124 +
   1.125 +typedef SkTLazy<SkPaint> SkLazyPaint;
   1.126 +
   1.127 +void SkCanvas::predrawNotify() {
   1.128 +    if (fSurfaceBase) {
   1.129 +        fSurfaceBase->aboutToDraw(SkSurface::kRetain_ContentChangeMode);
   1.130 +    }
   1.131 +}
   1.132 +
   1.133 +///////////////////////////////////////////////////////////////////////////////
   1.134 +
   1.135 +/*  This is the record we keep for each SkBaseDevice that the user installs.
   1.136 +    The clip/matrix/proc are fields that reflect the top of the save/restore
   1.137 +    stack. Whenever the canvas changes, it marks a dirty flag, and then before
   1.138 +    these are used (assuming we're not on a layer) we rebuild these cache
   1.139 +    values: they reflect the top of the save stack, but translated and clipped
   1.140 +    by the device's XY offset and bitmap-bounds.
   1.141 +*/
   1.142 +struct DeviceCM {
   1.143 +    DeviceCM*           fNext;
   1.144 +    SkBaseDevice*       fDevice;
   1.145 +    SkRasterClip        fClip;
   1.146 +    const SkMatrix*     fMatrix;
   1.147 +    SkPaint*            fPaint; // may be null (in the future)
   1.148 +
   1.149 +    DeviceCM(SkBaseDevice* device, int x, int y, const SkPaint* paint, SkCanvas* canvas)
   1.150 +            : fNext(NULL) {
   1.151 +        if (NULL != device) {
   1.152 +            device->ref();
   1.153 +            device->onAttachToCanvas(canvas);
   1.154 +        }
   1.155 +        fDevice = device;
   1.156 +        fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL;
   1.157 +    }
   1.158 +
   1.159 +    ~DeviceCM() {
   1.160 +        if (NULL != fDevice) {
   1.161 +            fDevice->onDetachFromCanvas();
   1.162 +            fDevice->unref();
   1.163 +        }
   1.164 +        SkDELETE(fPaint);
   1.165 +    }
   1.166 +
   1.167 +    void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
   1.168 +                  const SkClipStack& clipStack, SkRasterClip* updateClip) {
   1.169 +        int x = fDevice->getOrigin().x();
   1.170 +        int y = fDevice->getOrigin().y();
   1.171 +        int width = fDevice->width();
   1.172 +        int height = fDevice->height();
   1.173 +
   1.174 +        if ((x | y) == 0) {
   1.175 +            fMatrix = &totalMatrix;
   1.176 +            fClip = totalClip;
   1.177 +        } else {
   1.178 +            fMatrixStorage = totalMatrix;
   1.179 +            fMatrixStorage.postTranslate(SkIntToScalar(-x),
   1.180 +                                         SkIntToScalar(-y));
   1.181 +            fMatrix = &fMatrixStorage;
   1.182 +
   1.183 +            totalClip.translate(-x, -y, &fClip);
   1.184 +        }
   1.185 +
   1.186 +        fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
   1.187 +
   1.188 +        // intersect clip, but don't translate it (yet)
   1.189 +
   1.190 +        if (updateClip) {
   1.191 +            updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
   1.192 +                           SkRegion::kDifference_Op);
   1.193 +        }
   1.194 +
   1.195 +        fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
   1.196 +
   1.197 +#ifdef SK_DEBUG
   1.198 +        if (!fClip.isEmpty()) {
   1.199 +            SkIRect deviceR;
   1.200 +            deviceR.set(0, 0, width, height);
   1.201 +            SkASSERT(deviceR.contains(fClip.getBounds()));
   1.202 +        }
   1.203 +#endif
   1.204 +    }
   1.205 +
   1.206 +private:
   1.207 +    SkMatrix    fMatrixStorage;
   1.208 +};
   1.209 +
   1.210 +/*  This is the record we keep for each save/restore level in the stack.
   1.211 +    Since a level optionally copies the matrix and/or stack, we have pointers
   1.212 +    for these fields. If the value is copied for this level, the copy is
   1.213 +    stored in the ...Storage field, and the pointer points to that. If the
   1.214 +    value is not copied for this level, we ignore ...Storage, and just point
   1.215 +    at the corresponding value in the previous level in the stack.
   1.216 +*/
   1.217 +class SkCanvas::MCRec {
   1.218 +public:
   1.219 +    int             fFlags;
   1.220 +    SkMatrix*       fMatrix;        // points to either fMatrixStorage or prev MCRec
   1.221 +    SkRasterClip*   fRasterClip;    // points to either fRegionStorage or prev MCRec
   1.222 +    SkDrawFilter*   fFilter;        // the current filter (or null)
   1.223 +
   1.224 +    DeviceCM*   fLayer;
   1.225 +    /*  If there are any layers in the stack, this points to the top-most
   1.226 +        one that is at or below this level in the stack (so we know what
   1.227 +        bitmap/device to draw into from this level. This value is NOT
   1.228 +        reference counted, since the real owner is either our fLayer field,
   1.229 +        or a previous one in a lower level.)
   1.230 +    */
   1.231 +    DeviceCM*   fTopLayer;
   1.232 +
   1.233 +    MCRec(const MCRec* prev, int flags) : fFlags(flags) {
   1.234 +        if (NULL != prev) {
   1.235 +            if (flags & SkCanvas::kMatrix_SaveFlag) {
   1.236 +                fMatrixStorage = *prev->fMatrix;
   1.237 +                fMatrix = &fMatrixStorage;
   1.238 +            } else {
   1.239 +                fMatrix = prev->fMatrix;
   1.240 +            }
   1.241 +
   1.242 +            if (flags & SkCanvas::kClip_SaveFlag) {
   1.243 +                fRasterClipStorage = *prev->fRasterClip;
   1.244 +                fRasterClip = &fRasterClipStorage;
   1.245 +            } else {
   1.246 +                fRasterClip = prev->fRasterClip;
   1.247 +            }
   1.248 +
   1.249 +            fFilter = prev->fFilter;
   1.250 +            SkSafeRef(fFilter);
   1.251 +
   1.252 +            fTopLayer = prev->fTopLayer;
   1.253 +        } else {   // no prev
   1.254 +            fMatrixStorage.reset();
   1.255 +
   1.256 +            fMatrix     = &fMatrixStorage;
   1.257 +            fRasterClip = &fRasterClipStorage;
   1.258 +            fFilter     = NULL;
   1.259 +            fTopLayer   = NULL;
   1.260 +        }
   1.261 +        fLayer = NULL;
   1.262 +
   1.263 +        // don't bother initializing fNext
   1.264 +        inc_rec();
   1.265 +    }
   1.266 +    ~MCRec() {
   1.267 +        SkSafeUnref(fFilter);
   1.268 +        SkDELETE(fLayer);
   1.269 +        dec_rec();
   1.270 +    }
   1.271 +
   1.272 +private:
   1.273 +    SkMatrix        fMatrixStorage;
   1.274 +    SkRasterClip    fRasterClipStorage;
   1.275 +};
   1.276 +
   1.277 +class SkDrawIter : public SkDraw {
   1.278 +public:
   1.279 +    SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
   1.280 +        canvas = canvas->canvasForDrawIter();
   1.281 +        fCanvas = canvas;
   1.282 +        canvas->updateDeviceCMCache();
   1.283 +
   1.284 +        fClipStack = &canvas->fClipStack;
   1.285 +        fBounder = canvas->getBounder();
   1.286 +        fCurrLayer = canvas->fMCRec->fTopLayer;
   1.287 +        fSkipEmptyClips = skipEmptyClips;
   1.288 +    }
   1.289 +
   1.290 +    bool next() {
   1.291 +        // skip over recs with empty clips
   1.292 +        if (fSkipEmptyClips) {
   1.293 +            while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
   1.294 +                fCurrLayer = fCurrLayer->fNext;
   1.295 +            }
   1.296 +        }
   1.297 +
   1.298 +        const DeviceCM* rec = fCurrLayer;
   1.299 +        if (rec && rec->fDevice) {
   1.300 +
   1.301 +            fMatrix = rec->fMatrix;
   1.302 +            fClip   = &((SkRasterClip*)&rec->fClip)->forceGetBW();
   1.303 +            fRC     = &rec->fClip;
   1.304 +            fDevice = rec->fDevice;
   1.305 +            fBitmap = &fDevice->accessBitmap(true);
   1.306 +            fPaint  = rec->fPaint;
   1.307 +            SkDEBUGCODE(this->validate();)
   1.308 +
   1.309 +            fCurrLayer = rec->fNext;
   1.310 +            if (fBounder) {
   1.311 +                fBounder->setClip(fClip);
   1.312 +            }
   1.313 +            // fCurrLayer may be NULL now
   1.314 +
   1.315 +            return true;
   1.316 +        }
   1.317 +        return false;
   1.318 +    }
   1.319 +
   1.320 +    SkBaseDevice* getDevice() const { return fDevice; }
   1.321 +    int getX() const { return fDevice->getOrigin().x(); }
   1.322 +    int getY() const { return fDevice->getOrigin().y(); }
   1.323 +    const SkMatrix& getMatrix() const { return *fMatrix; }
   1.324 +    const SkRegion& getClip() const { return *fClip; }
   1.325 +    const SkPaint* getPaint() const { return fPaint; }
   1.326 +
   1.327 +private:
   1.328 +    SkCanvas*       fCanvas;
   1.329 +    const DeviceCM* fCurrLayer;
   1.330 +    const SkPaint*  fPaint;     // May be null.
   1.331 +    SkBool8         fSkipEmptyClips;
   1.332 +
   1.333 +    typedef SkDraw INHERITED;
   1.334 +};
   1.335 +
   1.336 +/////////////////////////////////////////////////////////////////////////////
   1.337 +
   1.338 +class AutoDrawLooper {
   1.339 +public:
   1.340 +    AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint,
   1.341 +                   bool skipLayerForImageFilter = false,
   1.342 +                   const SkRect* bounds = NULL) : fOrigPaint(paint) {
   1.343 +        fCanvas = canvas;
   1.344 +        fFilter = canvas->getDrawFilter();
   1.345 +        fPaint = NULL;
   1.346 +        fSaveCount = canvas->getSaveCount();
   1.347 +        fDoClearImageFilter = false;
   1.348 +        fDone = false;
   1.349 +
   1.350 +        if (!skipLayerForImageFilter && fOrigPaint.getImageFilter()) {
   1.351 +            SkPaint tmp;
   1.352 +            tmp.setImageFilter(fOrigPaint.getImageFilter());
   1.353 +            (void)canvas->internalSaveLayer(bounds, &tmp, SkCanvas::kARGB_ClipLayer_SaveFlag,
   1.354 +                                            true, SkCanvas::kFullLayer_SaveLayerStrategy);
   1.355 +            // we'll clear the imageFilter for the actual draws in next(), so
   1.356 +            // it will only be applied during the restore().
   1.357 +            fDoClearImageFilter = true;
   1.358 +        }
   1.359 +
   1.360 +        if (SkDrawLooper* looper = paint.getLooper()) {
   1.361 +            void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
   1.362 +                    looper->contextSize());
   1.363 +            fLooperContext = looper->createContext(canvas, buffer);
   1.364 +            fIsSimple = false;
   1.365 +        } else {
   1.366 +            fLooperContext = NULL;
   1.367 +            // can we be marked as simple?
   1.368 +            fIsSimple = !fFilter && !fDoClearImageFilter;
   1.369 +        }
   1.370 +    }
   1.371 +
   1.372 +    ~AutoDrawLooper() {
   1.373 +        if (fDoClearImageFilter) {
   1.374 +            fCanvas->internalRestore();
   1.375 +        }
   1.376 +        SkASSERT(fCanvas->getSaveCount() == fSaveCount);
   1.377 +    }
   1.378 +
   1.379 +    const SkPaint& paint() const {
   1.380 +        SkASSERT(fPaint);
   1.381 +        return *fPaint;
   1.382 +    }
   1.383 +
   1.384 +    bool next(SkDrawFilter::Type drawType) {
   1.385 +        if (fDone) {
   1.386 +            return false;
   1.387 +        } else if (fIsSimple) {
   1.388 +            fDone = true;
   1.389 +            fPaint = &fOrigPaint;
   1.390 +            return !fPaint->nothingToDraw();
   1.391 +        } else {
   1.392 +            return this->doNext(drawType);
   1.393 +        }
   1.394 +    }
   1.395 +
   1.396 +private:
   1.397 +    SkLazyPaint     fLazyPaint;
   1.398 +    SkCanvas*       fCanvas;
   1.399 +    const SkPaint&  fOrigPaint;
   1.400 +    SkDrawFilter*   fFilter;
   1.401 +    const SkPaint*  fPaint;
   1.402 +    int             fSaveCount;
   1.403 +    bool            fDoClearImageFilter;
   1.404 +    bool            fDone;
   1.405 +    bool            fIsSimple;
   1.406 +    SkDrawLooper::Context* fLooperContext;
   1.407 +    SkSmallAllocator<1, 32> fLooperContextAllocator;
   1.408 +
   1.409 +    bool doNext(SkDrawFilter::Type drawType);
   1.410 +};
   1.411 +
   1.412 +bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
   1.413 +    fPaint = NULL;
   1.414 +    SkASSERT(!fIsSimple);
   1.415 +    SkASSERT(fLooperContext || fFilter || fDoClearImageFilter);
   1.416 +
   1.417 +    SkPaint* paint = fLazyPaint.set(fOrigPaint);
   1.418 +
   1.419 +    if (fDoClearImageFilter) {
   1.420 +        paint->setImageFilter(NULL);
   1.421 +    }
   1.422 +
   1.423 +    if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
   1.424 +        fDone = true;
   1.425 +        return false;
   1.426 +    }
   1.427 +    if (fFilter) {
   1.428 +        if (!fFilter->filter(paint, drawType)) {
   1.429 +            fDone = true;
   1.430 +            return false;
   1.431 +        }
   1.432 +        if (NULL == fLooperContext) {
   1.433 +            // no looper means we only draw once
   1.434 +            fDone = true;
   1.435 +        }
   1.436 +    }
   1.437 +    fPaint = paint;
   1.438 +
   1.439 +    // if we only came in here for the imagefilter, mark us as done
   1.440 +    if (!fLooperContext && !fFilter) {
   1.441 +        fDone = true;
   1.442 +    }
   1.443 +
   1.444 +    // call this after any possible paint modifiers
   1.445 +    if (fPaint->nothingToDraw()) {
   1.446 +        fPaint = NULL;
   1.447 +        return false;
   1.448 +    }
   1.449 +    return true;
   1.450 +}
   1.451 +
   1.452 +/*  Stack helper for managing a SkBounder. In the destructor, if we were
   1.453 +    given a bounder, we call its commit() method, signifying that we are
   1.454 +    done accumulating bounds for that draw.
   1.455 +*/
   1.456 +class SkAutoBounderCommit {
   1.457 +public:
   1.458 +    SkAutoBounderCommit(SkBounder* bounder) : fBounder(bounder) {}
   1.459 +    ~SkAutoBounderCommit() {
   1.460 +        if (NULL != fBounder) {
   1.461 +            fBounder->commit();
   1.462 +        }
   1.463 +    }
   1.464 +private:
   1.465 +    SkBounder*  fBounder;
   1.466 +};
   1.467 +#define SkAutoBounderCommit(...) SK_REQUIRE_LOCAL_VAR(SkAutoBounderCommit)
   1.468 +
   1.469 +#include "SkColorPriv.h"
   1.470 +
   1.471 +////////// macros to place around the internal draw calls //////////////////
   1.472 +
   1.473 +#define LOOPER_BEGIN_DRAWDEVICE(paint, type)                        \
   1.474 +    this->predrawNotify();                                          \
   1.475 +    AutoDrawLooper  looper(this, paint, true);                      \
   1.476 +    while (looper.next(type)) {                                     \
   1.477 +        SkAutoBounderCommit ac(fBounder);                           \
   1.478 +        SkDrawIter          iter(this);
   1.479 +
   1.480 +#define LOOPER_BEGIN(paint, type, bounds)                           \
   1.481 +    this->predrawNotify();                                          \
   1.482 +    AutoDrawLooper  looper(this, paint, false, bounds);             \
   1.483 +    while (looper.next(type)) {                                     \
   1.484 +        SkAutoBounderCommit ac(fBounder);                           \
   1.485 +        SkDrawIter          iter(this);
   1.486 +
   1.487 +#define LOOPER_END    }
   1.488 +
   1.489 +////////////////////////////////////////////////////////////////////////////
   1.490 +
   1.491 +SkBaseDevice* SkCanvas::init(SkBaseDevice* device) {
   1.492 +    fBounder = NULL;
   1.493 +    fCachedLocalClipBounds.setEmpty();
   1.494 +    fCachedLocalClipBoundsDirty = true;
   1.495 +    fAllowSoftClip = true;
   1.496 +    fAllowSimplifyClip = false;
   1.497 +    fDeviceCMDirty = false;
   1.498 +    fSaveLayerCount = 0;
   1.499 +    fCullCount = 0;
   1.500 +    fMetaData = NULL;
   1.501 +
   1.502 +    fMCRec = (MCRec*)fMCStack.push_back();
   1.503 +    new (fMCRec) MCRec(NULL, 0);
   1.504 +
   1.505 +    fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL, NULL));
   1.506 +    fMCRec->fTopLayer = fMCRec->fLayer;
   1.507 +
   1.508 +    fSurfaceBase = NULL;
   1.509 +
   1.510 +    return this->setRootDevice(device);
   1.511 +}
   1.512 +
   1.513 +SkCanvas::SkCanvas()
   1.514 +    : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
   1.515 +{
   1.516 +    inc_canvas();
   1.517 +
   1.518 +    this->init(NULL);
   1.519 +}
   1.520 +
   1.521 +SkCanvas::SkCanvas(int width, int height)
   1.522 +    : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
   1.523 +{
   1.524 +    inc_canvas();
   1.525 +
   1.526 +    SkBitmap bitmap;
   1.527 +    bitmap.setConfig(SkImageInfo::MakeUnknown(width, height));
   1.528 +    this->init(SkNEW_ARGS(SkBitmapDevice, (bitmap)))->unref();
   1.529 +}
   1.530 +
   1.531 +SkCanvas::SkCanvas(SkBaseDevice* device)
   1.532 +    : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
   1.533 +{
   1.534 +    inc_canvas();
   1.535 +
   1.536 +    this->init(device);
   1.537 +}
   1.538 +
   1.539 +SkCanvas::SkCanvas(const SkBitmap& bitmap)
   1.540 +    : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
   1.541 +{
   1.542 +    inc_canvas();
   1.543 +
   1.544 +    this->init(SkNEW_ARGS(SkBitmapDevice, (bitmap)))->unref();
   1.545 +}
   1.546 +
   1.547 +SkCanvas::~SkCanvas() {
   1.548 +    // free up the contents of our deque
   1.549 +    this->restoreToCount(1);    // restore everything but the last
   1.550 +    SkASSERT(0 == fSaveLayerCount);
   1.551 +
   1.552 +    this->internalRestore();    // restore the last, since we're going away
   1.553 +
   1.554 +    SkSafeUnref(fBounder);
   1.555 +    SkDELETE(fMetaData);
   1.556 +
   1.557 +    dec_canvas();
   1.558 +}
   1.559 +
   1.560 +SkBounder* SkCanvas::setBounder(SkBounder* bounder) {
   1.561 +    SkRefCnt_SafeAssign(fBounder, bounder);
   1.562 +    return bounder;
   1.563 +}
   1.564 +
   1.565 +SkDrawFilter* SkCanvas::getDrawFilter() const {
   1.566 +    return fMCRec->fFilter;
   1.567 +}
   1.568 +
   1.569 +SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
   1.570 +    SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
   1.571 +    return filter;
   1.572 +}
   1.573 +
   1.574 +SkMetaData& SkCanvas::getMetaData() {
   1.575 +    // metadata users are rare, so we lazily allocate it. If that changes we
   1.576 +    // can decide to just make it a field in the device (rather than a ptr)
   1.577 +    if (NULL == fMetaData) {
   1.578 +        fMetaData = new SkMetaData;
   1.579 +    }
   1.580 +    return *fMetaData;
   1.581 +}
   1.582 +
   1.583 +///////////////////////////////////////////////////////////////////////////////
   1.584 +
   1.585 +void SkCanvas::flush() {
   1.586 +    SkBaseDevice* device = this->getDevice();
   1.587 +    if (device) {
   1.588 +        device->flush();
   1.589 +    }
   1.590 +}
   1.591 +
   1.592 +SkISize SkCanvas::getTopLayerSize() const {
   1.593 +    SkBaseDevice* d = this->getTopDevice();
   1.594 +    return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
   1.595 +}
   1.596 +
   1.597 +SkIPoint SkCanvas::getTopLayerOrigin() const {
   1.598 +    SkBaseDevice* d = this->getTopDevice();
   1.599 +    return d ? d->getOrigin() : SkIPoint::Make(0, 0);
   1.600 +}
   1.601 +
   1.602 +SkISize SkCanvas::getBaseLayerSize() const {
   1.603 +    SkBaseDevice* d = this->getDevice();
   1.604 +    return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
   1.605 +}
   1.606 +
   1.607 +SkBaseDevice* SkCanvas::getDevice() const {
   1.608 +    // return root device
   1.609 +    MCRec* rec = (MCRec*) fMCStack.front();
   1.610 +    SkASSERT(rec && rec->fLayer);
   1.611 +    return rec->fLayer->fDevice;
   1.612 +}
   1.613 +
   1.614 +SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
   1.615 +    if (updateMatrixClip) {
   1.616 +        const_cast<SkCanvas*>(this)->updateDeviceCMCache();
   1.617 +    }
   1.618 +    return fMCRec->fTopLayer->fDevice;
   1.619 +}
   1.620 +
   1.621 +SkBaseDevice* SkCanvas::setRootDevice(SkBaseDevice* device) {
   1.622 +    // return root device
   1.623 +    SkDeque::F2BIter iter(fMCStack);
   1.624 +    MCRec*           rec = (MCRec*)iter.next();
   1.625 +    SkASSERT(rec && rec->fLayer);
   1.626 +    SkBaseDevice*    rootDevice = rec->fLayer->fDevice;
   1.627 +
   1.628 +    if (rootDevice == device) {
   1.629 +        return device;
   1.630 +    }
   1.631 +
   1.632 +    if (device) {
   1.633 +        device->onAttachToCanvas(this);
   1.634 +    }
   1.635 +    if (rootDevice) {
   1.636 +        rootDevice->onDetachFromCanvas();
   1.637 +    }
   1.638 +
   1.639 +    SkRefCnt_SafeAssign(rec->fLayer->fDevice, device);
   1.640 +    rootDevice = device;
   1.641 +
   1.642 +    fDeviceCMDirty = true;
   1.643 +
   1.644 +    /*  Now we update our initial region to have the bounds of the new device,
   1.645 +        and then intersect all of the clips in our stack with these bounds,
   1.646 +        to ensure that we can't draw outside of the device's bounds (and trash
   1.647 +                                                                     memory).
   1.648 +
   1.649 +    NOTE: this is only a partial-fix, since if the new device is larger than
   1.650 +        the previous one, we don't know how to "enlarge" the clips in our stack,
   1.651 +        so drawing may be artificially restricted. Without keeping a history of
   1.652 +        all calls to canvas->clipRect() and canvas->clipPath(), we can't exactly
   1.653 +        reconstruct the correct clips, so this approximation will have to do.
   1.654 +        The caller really needs to restore() back to the base if they want to
   1.655 +        accurately take advantage of the new device bounds.
   1.656 +    */
   1.657 +
   1.658 +    SkIRect bounds;
   1.659 +    if (device) {
   1.660 +        bounds.set(0, 0, device->width(), device->height());
   1.661 +    } else {
   1.662 +        bounds.setEmpty();
   1.663 +    }
   1.664 +    // now jam our 1st clip to be bounds, and intersect the rest with that
   1.665 +    rec->fRasterClip->setRect(bounds);
   1.666 +    while ((rec = (MCRec*)iter.next()) != NULL) {
   1.667 +        (void)rec->fRasterClip->op(bounds, SkRegion::kIntersect_Op);
   1.668 +    }
   1.669 +
   1.670 +    return device;
   1.671 +}
   1.672 +
   1.673 +bool SkCanvas::readPixels(SkBitmap* bitmap,
   1.674 +                          int x, int y,
   1.675 +                          Config8888 config8888) {
   1.676 +    SkBaseDevice* device = this->getDevice();
   1.677 +    if (!device) {
   1.678 +        return false;
   1.679 +    }
   1.680 +    return device->readPixels(bitmap, x, y, config8888);
   1.681 +}
   1.682 +
   1.683 +bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
   1.684 +    SkBaseDevice* device = this->getDevice();
   1.685 +    if (!device) {
   1.686 +        return false;
   1.687 +    }
   1.688 +
   1.689 +    SkIRect bounds;
   1.690 +    bounds.set(0, 0, device->width(), device->height());
   1.691 +    if (!bounds.intersect(srcRect)) {
   1.692 +        return false;
   1.693 +    }
   1.694 +
   1.695 +    SkBitmap tmp;
   1.696 +    tmp.setConfig(SkBitmap::kARGB_8888_Config, bounds.width(),
   1.697 +                                               bounds.height());
   1.698 +    if (this->readPixels(&tmp, bounds.fLeft, bounds.fTop)) {
   1.699 +        bitmap->swap(tmp);
   1.700 +        return true;
   1.701 +    } else {
   1.702 +        return false;
   1.703 +    }
   1.704 +}
   1.705 +
   1.706 +#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
   1.707 +void SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y,
   1.708 +                           Config8888 config8888) {
   1.709 +    SkBaseDevice* device = this->getDevice();
   1.710 +    if (device) {
   1.711 +        if (SkIRect::Intersects(SkIRect::MakeSize(this->getDeviceSize()),
   1.712 +                                SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height()))) {
   1.713 +            device->accessBitmap(true);
   1.714 +            device->writePixels(bitmap, x, y, config8888);
   1.715 +        }
   1.716 +    }
   1.717 +}
   1.718 +#endif
   1.719 +
   1.720 +bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
   1.721 +    if (bitmap.getTexture()) {
   1.722 +        return false;
   1.723 +    }
   1.724 +    SkBitmap bm(bitmap);
   1.725 +    bm.lockPixels();
   1.726 +    if (bm.getPixels()) {
   1.727 +        return this->writePixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y);
   1.728 +    }
   1.729 +    return false;
   1.730 +}
   1.731 +
   1.732 +bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
   1.733 +                           int x, int y) {
   1.734 +    switch (origInfo.colorType()) {
   1.735 +        case kUnknown_SkColorType:
   1.736 +        case kIndex_8_SkColorType:
   1.737 +            return false;
   1.738 +        default:
   1.739 +            break;
   1.740 +    }
   1.741 +    if (NULL == pixels || rowBytes < origInfo.minRowBytes()) {
   1.742 +        return false;
   1.743 +    }
   1.744 +
   1.745 +    const SkISize size = this->getBaseLayerSize();
   1.746 +    SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
   1.747 +    if (!target.intersect(0, 0, size.width(), size.height())) {
   1.748 +        return false;
   1.749 +    }
   1.750 +
   1.751 +    SkBaseDevice* device = this->getDevice();
   1.752 +    if (!device) {
   1.753 +        return false;
   1.754 +    }
   1.755 +
   1.756 +    SkImageInfo info = origInfo;
   1.757 +    // the intersect may have shrunk info's logical size
   1.758 +    info.fWidth = target.width();
   1.759 +    info.fHeight = target.height();
   1.760 +
   1.761 +    // if x or y are negative, then we have to adjust pixels
   1.762 +    if (x > 0) {
   1.763 +        x = 0;
   1.764 +    }
   1.765 +    if (y > 0) {
   1.766 +        y = 0;
   1.767 +    }
   1.768 +    // here x,y are either 0 or negative
   1.769 +    pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
   1.770 +
   1.771 +    // The device can assert that the requested area is always contained in its bounds
   1.772 +    return device->writePixelsDirect(info, pixels, rowBytes, target.x(), target.y());
   1.773 +}
   1.774 +
   1.775 +SkCanvas* SkCanvas::canvasForDrawIter() {
   1.776 +    return this;
   1.777 +}
   1.778 +
   1.779 +//////////////////////////////////////////////////////////////////////////////
   1.780 +
   1.781 +void SkCanvas::updateDeviceCMCache() {
   1.782 +    if (fDeviceCMDirty) {
   1.783 +        const SkMatrix& totalMatrix = this->getTotalMatrix();
   1.784 +        const SkRasterClip& totalClip = *fMCRec->fRasterClip;
   1.785 +        DeviceCM*       layer = fMCRec->fTopLayer;
   1.786 +
   1.787 +        if (NULL == layer->fNext) {   // only one layer
   1.788 +            layer->updateMC(totalMatrix, totalClip, fClipStack, NULL);
   1.789 +        } else {
   1.790 +            SkRasterClip clip(totalClip);
   1.791 +            do {
   1.792 +                layer->updateMC(totalMatrix, clip, fClipStack, &clip);
   1.793 +            } while ((layer = layer->fNext) != NULL);
   1.794 +        }
   1.795 +        fDeviceCMDirty = false;
   1.796 +    }
   1.797 +}
   1.798 +
   1.799 +///////////////////////////////////////////////////////////////////////////////
   1.800 +
   1.801 +int SkCanvas::internalSave(SaveFlags flags) {
   1.802 +    int saveCount = this->getSaveCount(); // record this before the actual save
   1.803 +
   1.804 +    MCRec* newTop = (MCRec*)fMCStack.push_back();
   1.805 +    new (newTop) MCRec(fMCRec, flags);    // balanced in restore()
   1.806 +
   1.807 +    fMCRec = newTop;
   1.808 +
   1.809 +    if (SkCanvas::kClip_SaveFlag & flags) {
   1.810 +        fClipStack.save();
   1.811 +    }
   1.812 +
   1.813 +    return saveCount;
   1.814 +}
   1.815 +
   1.816 +void SkCanvas::willSave(SaveFlags) {
   1.817 +    // Do nothing. Subclasses may do something.
   1.818 +}
   1.819 +
   1.820 +int SkCanvas::save(SaveFlags flags) {
   1.821 +    this->willSave(flags);
   1.822 +    // call shared impl
   1.823 +    return this->internalSave(flags);
   1.824 +}
   1.825 +
   1.826 +static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
   1.827 +#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
   1.828 +    return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
   1.829 +#else
   1.830 +    return true;
   1.831 +#endif
   1.832 +}
   1.833 +
   1.834 +bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
   1.835 +                               SkIRect* intersection, const SkImageFilter* imageFilter) {
   1.836 +    SkIRect clipBounds;
   1.837 +    SkRegion::Op op = SkRegion::kIntersect_Op;
   1.838 +    if (!this->getClipDeviceBounds(&clipBounds)) {
   1.839 +        return false;
   1.840 +    }
   1.841 +
   1.842 +    if (imageFilter) {
   1.843 +        imageFilter->filterBounds(clipBounds, *fMCRec->fMatrix, &clipBounds);
   1.844 +        // Filters may grow the bounds beyond the device bounds.
   1.845 +        op = SkRegion::kReplace_Op;
   1.846 +    }
   1.847 +    SkIRect ir;
   1.848 +    if (NULL != bounds) {
   1.849 +        SkRect r;
   1.850 +
   1.851 +        this->getTotalMatrix().mapRect(&r, *bounds);
   1.852 +        r.roundOut(&ir);
   1.853 +        // early exit if the layer's bounds are clipped out
   1.854 +        if (!ir.intersect(clipBounds)) {
   1.855 +            if (bounds_affects_clip(flags)) {
   1.856 +                fMCRec->fRasterClip->setEmpty();
   1.857 +            }
   1.858 +            return false;
   1.859 +        }
   1.860 +    } else {    // no user bounds, so just use the clip
   1.861 +        ir = clipBounds;
   1.862 +    }
   1.863 +
   1.864 +    if (bounds_affects_clip(flags)) {
   1.865 +        fClipStack.clipDevRect(ir, op);
   1.866 +        // early exit if the clip is now empty
   1.867 +        if (!fMCRec->fRasterClip->op(ir, op)) {
   1.868 +            return false;
   1.869 +        }
   1.870 +    }
   1.871 +
   1.872 +    if (intersection) {
   1.873 +        *intersection = ir;
   1.874 +    }
   1.875 +    return true;
   1.876 +}
   1.877 +
   1.878 +SkCanvas::SaveLayerStrategy SkCanvas::willSaveLayer(const SkRect*, const SkPaint*, SaveFlags) {
   1.879 +
   1.880 +    // Do nothing. Subclasses may do something.
   1.881 +    return kFullLayer_SaveLayerStrategy;
   1.882 +}
   1.883 +
   1.884 +int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
   1.885 +                        SaveFlags flags) {
   1.886 +    // Overriding classes may return false to signal that we don't need to create a layer.
   1.887 +    SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags);
   1.888 +    return this->internalSaveLayer(bounds, paint, flags, false, strategy);
   1.889 +}
   1.890 +
   1.891 +static SkBaseDevice* createCompatibleDevice(SkCanvas* canvas,
   1.892 +                                            const SkImageInfo& info) {
   1.893 +    SkBaseDevice* device = canvas->getDevice();
   1.894 +    return device ? device->createCompatibleDevice(info) : NULL;
   1.895 +}
   1.896 +
   1.897 +int SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags,
   1.898 +                                bool justForImageFilter, SaveLayerStrategy strategy) {
   1.899 +#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
   1.900 +    flags = (SaveFlags)(flags | kClipToLayer_SaveFlag);
   1.901 +#endif
   1.902 +
   1.903 +    // do this before we create the layer. We don't call the public save() since
   1.904 +    // that would invoke a possibly overridden virtual
   1.905 +    int count = this->internalSave(flags);
   1.906 +
   1.907 +    fDeviceCMDirty = true;
   1.908 +
   1.909 +    SkIRect ir;
   1.910 +    if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : NULL)) {
   1.911 +        return count;
   1.912 +    }
   1.913 +
   1.914 +    // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
   1.915 +    // the clipRectBounds() call above?
   1.916 +    if (kNoLayer_SaveLayerStrategy == strategy) {
   1.917 +        return count;
   1.918 +    }
   1.919 +
   1.920 +    // Kill the imagefilter if our device doesn't allow it
   1.921 +    SkLazyPaint lazyP;
   1.922 +    if (paint && paint->getImageFilter()) {
   1.923 +        if (!this->getTopDevice()->allowImageFilter(paint->getImageFilter())) {
   1.924 +            if (justForImageFilter) {
   1.925 +                // early exit if the layer was just for the imageFilter
   1.926 +                return count;
   1.927 +            }
   1.928 +            SkPaint* p = lazyP.set(*paint);
   1.929 +            p->setImageFilter(NULL);
   1.930 +            paint = p;
   1.931 +        }
   1.932 +    }
   1.933 +
   1.934 +    bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag);
   1.935 +    SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
   1.936 +                        isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
   1.937 +
   1.938 +    SkBaseDevice* device;
   1.939 +    if (paint && paint->getImageFilter()) {
   1.940 +        device = createCompatibleDevice(this, info);
   1.941 +    } else {
   1.942 +        device = this->createLayerDevice(info);
   1.943 +    }
   1.944 +    if (NULL == device) {
   1.945 +        SkDebugf("Unable to create device for layer.");
   1.946 +        return count;
   1.947 +    }
   1.948 +
   1.949 +    device->setOrigin(ir.fLeft, ir.fTop);
   1.950 +    DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint, this));
   1.951 +    device->unref();
   1.952 +
   1.953 +    layer->fNext = fMCRec->fTopLayer;
   1.954 +    fMCRec->fLayer = layer;
   1.955 +    fMCRec->fTopLayer = layer;    // this field is NOT an owner of layer
   1.956 +
   1.957 +    fSaveLayerCount += 1;
   1.958 +    return count;
   1.959 +}
   1.960 +
   1.961 +int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
   1.962 +                             SaveFlags flags) {
   1.963 +    if (0xFF == alpha) {
   1.964 +        return this->saveLayer(bounds, NULL, flags);
   1.965 +    } else {
   1.966 +        SkPaint tmpPaint;
   1.967 +        tmpPaint.setAlpha(alpha);
   1.968 +        return this->saveLayer(bounds, &tmpPaint, flags);
   1.969 +    }
   1.970 +}
   1.971 +
   1.972 +void SkCanvas::willRestore() {
   1.973 +    // Do nothing. Subclasses may do something.
   1.974 +}
   1.975 +
   1.976 +void SkCanvas::restore() {
   1.977 +    // check for underflow
   1.978 +    if (fMCStack.count() > 1) {
   1.979 +        this->willRestore();
   1.980 +        this->internalRestore();
   1.981 +    }
   1.982 +}
   1.983 +
   1.984 +void SkCanvas::internalRestore() {
   1.985 +    SkASSERT(fMCStack.count() != 0);
   1.986 +
   1.987 +    fDeviceCMDirty = true;
   1.988 +    fCachedLocalClipBoundsDirty = true;
   1.989 +
   1.990 +    if (SkCanvas::kClip_SaveFlag & fMCRec->fFlags) {
   1.991 +        fClipStack.restore();
   1.992 +    }
   1.993 +
   1.994 +    // reserve our layer (if any)
   1.995 +    DeviceCM* layer = fMCRec->fLayer;   // may be null
   1.996 +    // now detach it from fMCRec so we can pop(). Gets freed after its drawn
   1.997 +    fMCRec->fLayer = NULL;
   1.998 +
   1.999 +    // now do the normal restore()
  1.1000 +    fMCRec->~MCRec();       // balanced in save()
  1.1001 +    fMCStack.pop_back();
  1.1002 +    fMCRec = (MCRec*)fMCStack.back();
  1.1003 +
  1.1004 +    /*  Time to draw the layer's offscreen. We can't call the public drawSprite,
  1.1005 +        since if we're being recorded, we don't want to record this (the
  1.1006 +        recorder will have already recorded the restore).
  1.1007 +    */
  1.1008 +    if (NULL != layer) {
  1.1009 +        if (layer->fNext) {
  1.1010 +            const SkIPoint& origin = layer->fDevice->getOrigin();
  1.1011 +            this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
  1.1012 +                                     layer->fPaint);
  1.1013 +            // reset this, since internalDrawDevice will have set it to true
  1.1014 +            fDeviceCMDirty = true;
  1.1015 +
  1.1016 +            SkASSERT(fSaveLayerCount > 0);
  1.1017 +            fSaveLayerCount -= 1;
  1.1018 +        }
  1.1019 +        SkDELETE(layer);
  1.1020 +    }
  1.1021 +}
  1.1022 +
  1.1023 +int SkCanvas::getSaveCount() const {
  1.1024 +    return fMCStack.count();
  1.1025 +}
  1.1026 +
  1.1027 +void SkCanvas::restoreToCount(int count) {
  1.1028 +    // sanity check
  1.1029 +    if (count < 1) {
  1.1030 +        count = 1;
  1.1031 +    }
  1.1032 +
  1.1033 +    int n = this->getSaveCount() - count;
  1.1034 +    for (int i = 0; i < n; ++i) {
  1.1035 +        this->restore();
  1.1036 +    }
  1.1037 +}
  1.1038 +
  1.1039 +bool SkCanvas::isDrawingToLayer() const {
  1.1040 +    return fSaveLayerCount > 0;
  1.1041 +}
  1.1042 +
  1.1043 +SkSurface* SkCanvas::newSurface(const SkImageInfo& info) {
  1.1044 +    return this->onNewSurface(info);
  1.1045 +}
  1.1046 +
  1.1047 +SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info) {
  1.1048 +    SkBaseDevice* dev = this->getDevice();
  1.1049 +    return dev ? dev->newSurface(info) : NULL;
  1.1050 +}
  1.1051 +
  1.1052 +SkImageInfo SkCanvas::imageInfo() const {
  1.1053 +    SkBaseDevice* dev = this->getDevice();
  1.1054 +    if (dev) {
  1.1055 +        return dev->imageInfo();
  1.1056 +    } else {
  1.1057 +        return SkImageInfo::MakeUnknown(0, 0);
  1.1058 +    }
  1.1059 +}
  1.1060 +
  1.1061 +const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
  1.1062 +    return this->onPeekPixels(info, rowBytes);
  1.1063 +}
  1.1064 +
  1.1065 +const void* SkCanvas::onPeekPixels(SkImageInfo* info, size_t* rowBytes) {
  1.1066 +    SkBaseDevice* dev = this->getDevice();
  1.1067 +    return dev ? dev->peekPixels(info, rowBytes) : NULL;
  1.1068 +}
  1.1069 +
  1.1070 +void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) {
  1.1071 +    return this->onAccessTopLayerPixels(info, rowBytes);
  1.1072 +}
  1.1073 +
  1.1074 +void* SkCanvas::onAccessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) {
  1.1075 +    SkBaseDevice* dev = this->getTopDevice();
  1.1076 +    return dev ? dev->accessPixels(info, rowBytes) : NULL;
  1.1077 +}
  1.1078 +
  1.1079 +SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
  1.1080 +    fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
  1.1081 +    if (NULL == fAddr) {
  1.1082 +        fInfo = canvas->imageInfo();
  1.1083 +        if (kUnknown_SkColorType == fInfo.colorType() ||
  1.1084 +            !fBitmap.allocPixels(fInfo))
  1.1085 +        {
  1.1086 +            return; // failure, fAddr is NULL
  1.1087 +        }
  1.1088 +        fBitmap.lockPixels();
  1.1089 +        if (!canvas->readPixels(&fBitmap, 0, 0)) {
  1.1090 +            return; // failure, fAddr is NULL
  1.1091 +        }
  1.1092 +        fAddr = fBitmap.getPixels();
  1.1093 +        fRowBytes = fBitmap.rowBytes();
  1.1094 +    }
  1.1095 +    SkASSERT(fAddr);    // success
  1.1096 +}
  1.1097 +
  1.1098 +bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
  1.1099 +    if (fAddr) {
  1.1100 +        return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes,
  1.1101 +                                     NULL, NULL);
  1.1102 +    } else {
  1.1103 +        bitmap->reset();
  1.1104 +        return false;
  1.1105 +    }
  1.1106 +}
  1.1107 +
  1.1108 +void SkCanvas::onPushCull(const SkRect& cullRect) {
  1.1109 +    // do nothing. Subclasses may do something
  1.1110 +}
  1.1111 +
  1.1112 +void SkCanvas::onPopCull() {
  1.1113 +    // do nothing. Subclasses may do something
  1.1114 +}
  1.1115 +
  1.1116 +/////////////////////////////////////////////////////////////////////////////
  1.1117 +
  1.1118 +void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap,
  1.1119 +                                const SkMatrix& matrix, const SkPaint* paint) {
  1.1120 +    if (bitmap.drawsNothing()) {
  1.1121 +        return;
  1.1122 +    }
  1.1123 +
  1.1124 +    SkLazyPaint lazy;
  1.1125 +    if (NULL == paint) {
  1.1126 +        paint = lazy.init();
  1.1127 +    }
  1.1128 +
  1.1129 +    SkDEBUGCODE(bitmap.validate();)
  1.1130 +    CHECK_LOCKCOUNT_BALANCE(bitmap);
  1.1131 +
  1.1132 +    SkRect storage;
  1.1133 +    const SkRect* bounds = NULL;
  1.1134 +    if (paint && paint->canComputeFastBounds()) {
  1.1135 +        bitmap.getBounds(&storage);
  1.1136 +        matrix.mapRect(&storage);
  1.1137 +        bounds = &paint->computeFastBounds(storage, &storage);
  1.1138 +    }
  1.1139 +
  1.1140 +    LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
  1.1141 +
  1.1142 +    while (iter.next()) {
  1.1143 +        iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
  1.1144 +    }
  1.1145 +
  1.1146 +    LOOPER_END
  1.1147 +}
  1.1148 +
  1.1149 +void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
  1.1150 +                                  const SkPaint* paint) {
  1.1151 +    SkPaint tmp;
  1.1152 +    if (NULL == paint) {
  1.1153 +        tmp.setDither(true);
  1.1154 +        paint = &tmp;
  1.1155 +    }
  1.1156 +
  1.1157 +    LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
  1.1158 +    while (iter.next()) {
  1.1159 +        SkBaseDevice* dstDev = iter.fDevice;
  1.1160 +        paint = &looper.paint();
  1.1161 +        SkImageFilter* filter = paint->getImageFilter();
  1.1162 +        SkIPoint pos = { x - iter.getX(), y - iter.getY() };
  1.1163 +        if (filter && !dstDev->canHandleImageFilter(filter)) {
  1.1164 +            SkDeviceImageFilterProxy proxy(dstDev);
  1.1165 +            SkBitmap dst;
  1.1166 +            SkIPoint offset = SkIPoint::Make(0, 0);
  1.1167 +            const SkBitmap& src = srcDev->accessBitmap(false);
  1.1168 +            SkMatrix matrix = *iter.fMatrix;
  1.1169 +            matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y));
  1.1170 +            SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
  1.1171 +            SkImageFilter::Context ctx(matrix, clipBounds);
  1.1172 +            if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
  1.1173 +                SkPaint tmpUnfiltered(*paint);
  1.1174 +                tmpUnfiltered.setImageFilter(NULL);
  1.1175 +                dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
  1.1176 +                                   tmpUnfiltered);
  1.1177 +            }
  1.1178 +        } else {
  1.1179 +            dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
  1.1180 +        }
  1.1181 +    }
  1.1182 +    LOOPER_END
  1.1183 +}
  1.1184 +
  1.1185 +void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y,
  1.1186 +                          const SkPaint* paint) {
  1.1187 +    if (bitmap.drawsNothing()) {
  1.1188 +        return;
  1.1189 +    }
  1.1190 +    SkDEBUGCODE(bitmap.validate();)
  1.1191 +    CHECK_LOCKCOUNT_BALANCE(bitmap);
  1.1192 +
  1.1193 +    SkPaint tmp;
  1.1194 +    if (NULL == paint) {
  1.1195 +        paint = &tmp;
  1.1196 +    }
  1.1197 +
  1.1198 +    LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
  1.1199 +
  1.1200 +    while (iter.next()) {
  1.1201 +        paint = &looper.paint();
  1.1202 +        SkImageFilter* filter = paint->getImageFilter();
  1.1203 +        SkIPoint pos = { x - iter.getX(), y - iter.getY() };
  1.1204 +        if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
  1.1205 +            SkDeviceImageFilterProxy proxy(iter.fDevice);
  1.1206 +            SkBitmap dst;
  1.1207 +            SkIPoint offset = SkIPoint::Make(0, 0);
  1.1208 +            SkMatrix matrix = *iter.fMatrix;
  1.1209 +            matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y));
  1.1210 +            SkIRect clipBounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
  1.1211 +            SkImageFilter::Context ctx(matrix, clipBounds);
  1.1212 +            if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) {
  1.1213 +                SkPaint tmpUnfiltered(*paint);
  1.1214 +                tmpUnfiltered.setImageFilter(NULL);
  1.1215 +                iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
  1.1216 +                                         tmpUnfiltered);
  1.1217 +            }
  1.1218 +        } else {
  1.1219 +            iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
  1.1220 +        }
  1.1221 +    }
  1.1222 +    LOOPER_END
  1.1223 +}
  1.1224 +
  1.1225 +/////////////////////////////////////////////////////////////////////////////
  1.1226 +void SkCanvas::didTranslate(SkScalar, SkScalar) {
  1.1227 +    // Do nothing. Subclasses may do something.
  1.1228 +}
  1.1229 +
  1.1230 +bool SkCanvas::translate(SkScalar dx, SkScalar dy) {
  1.1231 +    fDeviceCMDirty = true;
  1.1232 +    fCachedLocalClipBoundsDirty = true;
  1.1233 +    bool res = fMCRec->fMatrix->preTranslate(dx, dy);
  1.1234 +
  1.1235 +    this->didTranslate(dx, dy);
  1.1236 +    return res;
  1.1237 +}
  1.1238 +
  1.1239 +void SkCanvas::didScale(SkScalar, SkScalar) {
  1.1240 +    // Do nothing. Subclasses may do something.
  1.1241 +}
  1.1242 +
  1.1243 +bool SkCanvas::scale(SkScalar sx, SkScalar sy) {
  1.1244 +    fDeviceCMDirty = true;
  1.1245 +    fCachedLocalClipBoundsDirty = true;
  1.1246 +    bool res = fMCRec->fMatrix->preScale(sx, sy);
  1.1247 +
  1.1248 +    this->didScale(sx, sy);
  1.1249 +    return res;
  1.1250 +}
  1.1251 +
  1.1252 +void SkCanvas::didRotate(SkScalar) {
  1.1253 +    // Do nothing. Subclasses may do something.
  1.1254 +}
  1.1255 +
  1.1256 +bool SkCanvas::rotate(SkScalar degrees) {
  1.1257 +    fDeviceCMDirty = true;
  1.1258 +    fCachedLocalClipBoundsDirty = true;
  1.1259 +    bool res = fMCRec->fMatrix->preRotate(degrees);
  1.1260 +
  1.1261 +    this->didRotate(degrees);
  1.1262 +    return res;
  1.1263 +}
  1.1264 +
  1.1265 +void SkCanvas::didSkew(SkScalar, SkScalar) {
  1.1266 +    // Do nothing. Subclasses may do something.
  1.1267 +}
  1.1268 +
  1.1269 +bool SkCanvas::skew(SkScalar sx, SkScalar sy) {
  1.1270 +    fDeviceCMDirty = true;
  1.1271 +    fCachedLocalClipBoundsDirty = true;
  1.1272 +    bool res = fMCRec->fMatrix->preSkew(sx, sy);
  1.1273 +
  1.1274 +    this->didSkew(sx, sy);
  1.1275 +    return res;
  1.1276 +}
  1.1277 +
  1.1278 +void SkCanvas::didConcat(const SkMatrix&) {
  1.1279 +    // Do nothing. Subclasses may do something.
  1.1280 +}
  1.1281 +
  1.1282 +bool SkCanvas::concat(const SkMatrix& matrix) {
  1.1283 +    fDeviceCMDirty = true;
  1.1284 +    fCachedLocalClipBoundsDirty = true;
  1.1285 +    bool res = fMCRec->fMatrix->preConcat(matrix);
  1.1286 +
  1.1287 +    this->didConcat(matrix);
  1.1288 +    return res;
  1.1289 +}
  1.1290 +
  1.1291 +void SkCanvas::didSetMatrix(const SkMatrix&) {
  1.1292 +    // Do nothing. Subclasses may do something.
  1.1293 +}
  1.1294 +
  1.1295 +void SkCanvas::setMatrix(const SkMatrix& matrix) {
  1.1296 +    fDeviceCMDirty = true;
  1.1297 +    fCachedLocalClipBoundsDirty = true;
  1.1298 +    *fMCRec->fMatrix = matrix;
  1.1299 +    this->didSetMatrix(matrix);
  1.1300 +}
  1.1301 +
  1.1302 +void SkCanvas::resetMatrix() {
  1.1303 +    SkMatrix matrix;
  1.1304 +
  1.1305 +    matrix.reset();
  1.1306 +    this->setMatrix(matrix);
  1.1307 +}
  1.1308 +
  1.1309 +//////////////////////////////////////////////////////////////////////////////
  1.1310 +
  1.1311 +void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
  1.1312 +    ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
  1.1313 +    this->onClipRect(rect, op, edgeStyle);
  1.1314 +}
  1.1315 +
  1.1316 +void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
  1.1317 +#ifdef SK_ENABLE_CLIP_QUICKREJECT
  1.1318 +    if (SkRegion::kIntersect_Op == op) {
  1.1319 +        if (fMCRec->fRasterClip->isEmpty()) {
  1.1320 +            return false;
  1.1321 +        }
  1.1322 +
  1.1323 +        if (this->quickReject(rect)) {
  1.1324 +            fDeviceCMDirty = true;
  1.1325 +            fCachedLocalClipBoundsDirty = true;
  1.1326 +
  1.1327 +            fClipStack.clipEmpty();
  1.1328 +            return fMCRec->fRasterClip->setEmpty();
  1.1329 +        }
  1.1330 +    }
  1.1331 +#endif
  1.1332 +
  1.1333 +    AutoValidateClip avc(this);
  1.1334 +
  1.1335 +    fDeviceCMDirty = true;
  1.1336 +    fCachedLocalClipBoundsDirty = true;
  1.1337 +    if (!fAllowSoftClip) {
  1.1338 +        edgeStyle = kHard_ClipEdgeStyle;
  1.1339 +    }
  1.1340 +
  1.1341 +    if (fMCRec->fMatrix->rectStaysRect()) {
  1.1342 +        // for these simpler matrices, we can stay a rect even after applying
  1.1343 +        // the matrix. This means we don't have to a) make a path, and b) tell
  1.1344 +        // the region code to scan-convert the path, only to discover that it
  1.1345 +        // is really just a rect.
  1.1346 +        SkRect      r;
  1.1347 +
  1.1348 +        fMCRec->fMatrix->mapRect(&r, rect);
  1.1349 +        fClipStack.clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle);
  1.1350 +        fMCRec->fRasterClip->op(r, op, kSoft_ClipEdgeStyle == edgeStyle);
  1.1351 +    } else {
  1.1352 +        // since we're rotated or some such thing, we convert the rect to a path
  1.1353 +        // and clip against that, since it can handle any matrix. However, to
  1.1354 +        // avoid recursion in the case where we are subclassed (e.g. Pictures)
  1.1355 +        // we explicitly call "our" version of clipPath.
  1.1356 +        SkPath  path;
  1.1357 +
  1.1358 +        path.addRect(rect);
  1.1359 +        this->SkCanvas::onClipPath(path, op, edgeStyle);
  1.1360 +    }
  1.1361 +}
  1.1362 +
  1.1363 +static void clip_path_helper(const SkCanvas* canvas, SkRasterClip* currClip,
  1.1364 +                             const SkPath& devPath, SkRegion::Op op, bool doAA) {
  1.1365 +    // base is used to limit the size (and therefore memory allocation) of the
  1.1366 +    // region that results from scan converting devPath.
  1.1367 +    SkRegion base;
  1.1368 +
  1.1369 +    if (SkRegion::kIntersect_Op == op) {
  1.1370 +        // since we are intersect, we can do better (tighter) with currRgn's
  1.1371 +        // bounds, than just using the device. However, if currRgn is complex,
  1.1372 +        // our region blitter may hork, so we do that case in two steps.
  1.1373 +        if (currClip->isRect()) {
  1.1374 +            // FIXME: we should also be able to do this when currClip->isBW(),
  1.1375 +            // but relaxing the test above triggers GM asserts in
  1.1376 +            // SkRgnBuilder::blitH(). We need to investigate what's going on.
  1.1377 +            currClip->setPath(devPath, currClip->bwRgn(), doAA);
  1.1378 +        } else {
  1.1379 +            base.setRect(currClip->getBounds());
  1.1380 +            SkRasterClip clip;
  1.1381 +            clip.setPath(devPath, base, doAA);
  1.1382 +            currClip->op(clip, op);
  1.1383 +        }
  1.1384 +    } else {
  1.1385 +        const SkBaseDevice* device = canvas->getDevice();
  1.1386 +        if (!device) {
  1.1387 +            currClip->setEmpty();
  1.1388 +            return;
  1.1389 +        }
  1.1390 +
  1.1391 +        base.setRect(0, 0, device->width(), device->height());
  1.1392 +
  1.1393 +        if (SkRegion::kReplace_Op == op) {
  1.1394 +            currClip->setPath(devPath, base, doAA);
  1.1395 +        } else {
  1.1396 +            SkRasterClip clip;
  1.1397 +            clip.setPath(devPath, base, doAA);
  1.1398 +            currClip->op(clip, op);
  1.1399 +        }
  1.1400 +    }
  1.1401 +}
  1.1402 +
  1.1403 +void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
  1.1404 +    ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
  1.1405 +    if (rrect.isRect()) {
  1.1406 +        this->onClipRect(rrect.getBounds(), op, edgeStyle);
  1.1407 +    } else {
  1.1408 +        this->onClipRRect(rrect, op, edgeStyle);
  1.1409 +    }
  1.1410 +}
  1.1411 +
  1.1412 +void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
  1.1413 +    SkRRect transformedRRect;
  1.1414 +    if (rrect.transform(*fMCRec->fMatrix, &transformedRRect)) {
  1.1415 +        AutoValidateClip avc(this);
  1.1416 +
  1.1417 +        fDeviceCMDirty = true;
  1.1418 +        fCachedLocalClipBoundsDirty = true;
  1.1419 +        if (!fAllowSoftClip) {
  1.1420 +            edgeStyle = kHard_ClipEdgeStyle;
  1.1421 +        }
  1.1422 +
  1.1423 +        fClipStack.clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
  1.1424 +
  1.1425 +        SkPath devPath;
  1.1426 +        devPath.addRRect(transformedRRect);
  1.1427 +
  1.1428 +        clip_path_helper(this, fMCRec->fRasterClip, devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
  1.1429 +        return;
  1.1430 +    }
  1.1431 +
  1.1432 +    SkPath path;
  1.1433 +    path.addRRect(rrect);
  1.1434 +    // call the non-virtual version
  1.1435 +    this->SkCanvas::onClipPath(path, op, edgeStyle);
  1.1436 +}
  1.1437 +
  1.1438 +void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
  1.1439 +    ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
  1.1440 +    SkRect r;
  1.1441 +    if (!path.isInverseFillType() && path.isRect(&r)) {
  1.1442 +        this->onClipRect(r, op, edgeStyle);
  1.1443 +    } else {
  1.1444 +        this->onClipPath(path, op, edgeStyle);
  1.1445 +    }
  1.1446 +}
  1.1447 +
  1.1448 +void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
  1.1449 +#ifdef SK_ENABLE_CLIP_QUICKREJECT
  1.1450 +    if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
  1.1451 +        if (fMCRec->fRasterClip->isEmpty()) {
  1.1452 +            return false;
  1.1453 +        }
  1.1454 +
  1.1455 +        if (this->quickReject(path.getBounds())) {
  1.1456 +            fDeviceCMDirty = true;
  1.1457 +            fCachedLocalClipBoundsDirty = true;
  1.1458 +
  1.1459 +            fClipStack.clipEmpty();
  1.1460 +            return fMCRec->fRasterClip->setEmpty();
  1.1461 +        }
  1.1462 +    }
  1.1463 +#endif
  1.1464 +
  1.1465 +    AutoValidateClip avc(this);
  1.1466 +
  1.1467 +    fDeviceCMDirty = true;
  1.1468 +    fCachedLocalClipBoundsDirty = true;
  1.1469 +    if (!fAllowSoftClip) {
  1.1470 +        edgeStyle = kHard_ClipEdgeStyle;
  1.1471 +    }
  1.1472 +
  1.1473 +    SkPath devPath;
  1.1474 +    path.transform(*fMCRec->fMatrix, &devPath);
  1.1475 +
  1.1476 +    // Check if the transfomation, or the original path itself
  1.1477 +    // made us empty. Note this can also happen if we contained NaN
  1.1478 +    // values. computing the bounds detects this, and will set our
  1.1479 +    // bounds to empty if that is the case. (see SkRect::set(pts, count))
  1.1480 +    if (devPath.getBounds().isEmpty()) {
  1.1481 +        // resetting the path will remove any NaN or other wanky values
  1.1482 +        // that might upset our scan converter.
  1.1483 +        devPath.reset();
  1.1484 +    }
  1.1485 +
  1.1486 +    // if we called path.swap() we could avoid a deep copy of this path
  1.1487 +    fClipStack.clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
  1.1488 +
  1.1489 +    if (fAllowSimplifyClip) {
  1.1490 +        devPath.reset();
  1.1491 +        devPath.setFillType(SkPath::kInverseEvenOdd_FillType);
  1.1492 +        const SkClipStack* clipStack = getClipStack();
  1.1493 +        SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterStart);
  1.1494 +        const SkClipStack::Element* element;
  1.1495 +        while ((element = iter.next())) {
  1.1496 +            SkClipStack::Element::Type type = element->getType();
  1.1497 +            if (type == SkClipStack::Element::kEmpty_Type) {
  1.1498 +                continue;
  1.1499 +            }
  1.1500 +            SkPath operand;
  1.1501 +            element->asPath(&operand);
  1.1502 +            SkRegion::Op elementOp = element->getOp();
  1.1503 +            if (elementOp == SkRegion::kReplace_Op) {
  1.1504 +                devPath = operand;
  1.1505 +            } else {
  1.1506 +                Op(devPath, operand, (SkPathOp) elementOp, &devPath);
  1.1507 +            }
  1.1508 +            // if the prev and curr clips disagree about aa -vs- not, favor the aa request.
  1.1509 +            // perhaps we need an API change to avoid this sort of mixed-signals about
  1.1510 +            // clipping.
  1.1511 +            if (element->isAA()) {
  1.1512 +                edgeStyle = kSoft_ClipEdgeStyle;
  1.1513 +            }
  1.1514 +        }
  1.1515 +        op = SkRegion::kReplace_Op;
  1.1516 +    }
  1.1517 +
  1.1518 +    clip_path_helper(this, fMCRec->fRasterClip, devPath, op, edgeStyle);
  1.1519 +}
  1.1520 +
  1.1521 +void SkCanvas::updateClipConservativelyUsingBounds(const SkRect& bounds, SkRegion::Op op,
  1.1522 +                                                   bool inverseFilled) {
  1.1523 +    // This is for updating the clip conservatively using only bounds
  1.1524 +    // information.
  1.1525 +    // Contract:
  1.1526 +    //    The current clip must contain the true clip. The true
  1.1527 +    //    clip is the clip that would have normally been computed
  1.1528 +    //    by calls to clipPath and clipRRect
  1.1529 +    // Objective:
  1.1530 +    //    Keep the current clip as small as possible without
  1.1531 +    //    breaking the contract, using only clip bounding rectangles
  1.1532 +    //    (for performance).
  1.1533 +
  1.1534 +    // N.B.: This *never* calls back through a virtual on canvas, so subclasses
  1.1535 +    // don't have to worry about getting caught in a loop. Thus anywhere
  1.1536 +    // we call a virtual method, we explicitly prefix it with
  1.1537 +    // SkCanvas:: to be sure to call the base-class.
  1.1538 +
  1.1539 +    if (inverseFilled) {
  1.1540 +        switch (op) {
  1.1541 +            case SkRegion::kIntersect_Op:
  1.1542 +            case SkRegion::kDifference_Op:
  1.1543 +                // These ops can only shrink the current clip. So leaving
  1.1544 +                // the clip unchanged conservatively respects the contract.
  1.1545 +                break;
  1.1546 +            case SkRegion::kUnion_Op:
  1.1547 +            case SkRegion::kReplace_Op:
  1.1548 +            case SkRegion::kReverseDifference_Op:
  1.1549 +            case SkRegion::kXOR_Op: {
  1.1550 +                    // These ops can grow the current clip up to the extents of
  1.1551 +                    // the input clip, which is inverse filled, so we just set
  1.1552 +                    // the current clip to the device bounds.
  1.1553 +                    SkRect deviceBounds;
  1.1554 +                    SkIRect deviceIBounds;
  1.1555 +                    this->getDevice()->getGlobalBounds(&deviceIBounds);
  1.1556 +                    deviceBounds = SkRect::Make(deviceIBounds);
  1.1557 +                    this->SkCanvas::save(SkCanvas::kMatrix_SaveFlag);
  1.1558 +                    // set the clip in device space
  1.1559 +                    this->SkCanvas::setMatrix(SkMatrix::I());
  1.1560 +                    this->SkCanvas::onClipRect(deviceBounds, SkRegion::kReplace_Op,
  1.1561 +                                               kHard_ClipEdgeStyle);
  1.1562 +                    this->SkCanvas::restore(); //pop the matrix, but keep the clip
  1.1563 +                    break;
  1.1564 +            }
  1.1565 +            default:
  1.1566 +                SkASSERT(0); // unhandled op?
  1.1567 +        }
  1.1568 +    } else {
  1.1569 +        // Not inverse filled
  1.1570 +        switch (op) {
  1.1571 +            case SkRegion::kIntersect_Op:
  1.1572 +            case SkRegion::kUnion_Op:
  1.1573 +            case SkRegion::kReplace_Op:
  1.1574 +                this->SkCanvas::onClipRect(bounds, op, kHard_ClipEdgeStyle);
  1.1575 +                break;
  1.1576 +            case SkRegion::kDifference_Op:
  1.1577 +                // Difference can only shrink the current clip.
  1.1578 +                // Leaving clip unchanged conservatively fullfills the contract.
  1.1579 +                break;
  1.1580 +            case SkRegion::kReverseDifference_Op:
  1.1581 +                // To reverse, we swap in the bounds with a replace op.
  1.1582 +                // As with difference, leave it unchanged.
  1.1583 +                this->SkCanvas::onClipRect(bounds, SkRegion::kReplace_Op, kHard_ClipEdgeStyle);
  1.1584 +                break;
  1.1585 +            case SkRegion::kXOR_Op:
  1.1586 +                // Be conservative, based on (A XOR B) always included in (A union B),
  1.1587 +                // which is always included in (bounds(A) union bounds(B))
  1.1588 +                this->SkCanvas::onClipRect(bounds, SkRegion::kUnion_Op, kHard_ClipEdgeStyle);
  1.1589 +                break;
  1.1590 +            default:
  1.1591 +                SkASSERT(0); // unhandled op?
  1.1592 +        }
  1.1593 +    }
  1.1594 +}
  1.1595 +
  1.1596 +void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
  1.1597 +    this->onClipRegion(rgn, op);
  1.1598 +}
  1.1599 +
  1.1600 +void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
  1.1601 +    AutoValidateClip avc(this);
  1.1602 +
  1.1603 +    fDeviceCMDirty = true;
  1.1604 +    fCachedLocalClipBoundsDirty = true;
  1.1605 +
  1.1606 +    // todo: signal fClipStack that we have a region, and therefore (I guess)
  1.1607 +    // we have to ignore it, and use the region directly?
  1.1608 +    fClipStack.clipDevRect(rgn.getBounds(), op);
  1.1609 +
  1.1610 +    fMCRec->fRasterClip->op(rgn, op);
  1.1611 +}
  1.1612 +
  1.1613 +#ifdef SK_DEBUG
  1.1614 +void SkCanvas::validateClip() const {
  1.1615 +    // construct clipRgn from the clipstack
  1.1616 +    const SkBaseDevice* device = this->getDevice();
  1.1617 +    if (!device) {
  1.1618 +        SkASSERT(this->isClipEmpty());
  1.1619 +        return;
  1.1620 +    }
  1.1621 +
  1.1622 +    SkIRect ir;
  1.1623 +    ir.set(0, 0, device->width(), device->height());
  1.1624 +    SkRasterClip tmpClip(ir);
  1.1625 +
  1.1626 +    SkClipStack::B2TIter                iter(fClipStack);
  1.1627 +    const SkClipStack::Element* element;
  1.1628 +    while ((element = iter.next()) != NULL) {
  1.1629 +        switch (element->getType()) {
  1.1630 +            case SkClipStack::Element::kRect_Type:
  1.1631 +                element->getRect().round(&ir);
  1.1632 +                tmpClip.op(ir, element->getOp());
  1.1633 +                break;
  1.1634 +            case SkClipStack::Element::kEmpty_Type:
  1.1635 +                tmpClip.setEmpty();
  1.1636 +                break;
  1.1637 +            default: {
  1.1638 +                SkPath path;
  1.1639 +                element->asPath(&path);
  1.1640 +                clip_path_helper(this, &tmpClip, path, element->getOp(), element->isAA());
  1.1641 +                break;
  1.1642 +            }
  1.1643 +        }
  1.1644 +    }
  1.1645 +}
  1.1646 +#endif
  1.1647 +
  1.1648 +void SkCanvas::replayClips(ClipVisitor* visitor) const {
  1.1649 +    SkClipStack::B2TIter                iter(fClipStack);
  1.1650 +    const SkClipStack::Element*         element;
  1.1651 +
  1.1652 +    static const SkRect kEmpty = { 0, 0, 0, 0 };
  1.1653 +    while ((element = iter.next()) != NULL) {
  1.1654 +        switch (element->getType()) {
  1.1655 +            case SkClipStack::Element::kPath_Type:
  1.1656 +                visitor->clipPath(element->getPath(), element->getOp(), element->isAA());
  1.1657 +                break;
  1.1658 +            case SkClipStack::Element::kRRect_Type:
  1.1659 +                visitor->clipRRect(element->getRRect(), element->getOp(), element->isAA());
  1.1660 +                break;
  1.1661 +            case SkClipStack::Element::kRect_Type:
  1.1662 +                visitor->clipRect(element->getRect(), element->getOp(), element->isAA());
  1.1663 +                break;
  1.1664 +            case SkClipStack::Element::kEmpty_Type:
  1.1665 +                visitor->clipRect(kEmpty, SkRegion::kIntersect_Op, false);
  1.1666 +                break;
  1.1667 +        }
  1.1668 +    }
  1.1669 +}
  1.1670 +
  1.1671 +///////////////////////////////////////////////////////////////////////////////
  1.1672 +
  1.1673 +bool SkCanvas::isClipEmpty() const {
  1.1674 +    return fMCRec->fRasterClip->isEmpty();
  1.1675 +}
  1.1676 +
  1.1677 +bool SkCanvas::isClipRect() const {
  1.1678 +    return fMCRec->fRasterClip->isRect();
  1.1679 +}
  1.1680 +
  1.1681 +bool SkCanvas::quickReject(const SkRect& rect) const {
  1.1682 +
  1.1683 +    if (!rect.isFinite())
  1.1684 +        return true;
  1.1685 +
  1.1686 +    if (fMCRec->fRasterClip->isEmpty()) {
  1.1687 +        return true;
  1.1688 +    }
  1.1689 +
  1.1690 +    if (fMCRec->fMatrix->hasPerspective()) {
  1.1691 +        SkRect dst;
  1.1692 +        fMCRec->fMatrix->mapRect(&dst, rect);
  1.1693 +        SkIRect idst;
  1.1694 +        dst.roundOut(&idst);
  1.1695 +        return !SkIRect::Intersects(idst, fMCRec->fRasterClip->getBounds());
  1.1696 +    } else {
  1.1697 +        const SkRect& clipR = this->getLocalClipBounds();
  1.1698 +
  1.1699 +        // for speed, do the most likely reject compares first
  1.1700 +        // TODO: should we use | instead, or compare all 4 at once?
  1.1701 +        if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
  1.1702 +            return true;
  1.1703 +        }
  1.1704 +        if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
  1.1705 +            return true;
  1.1706 +        }
  1.1707 +        return false;
  1.1708 +    }
  1.1709 +}
  1.1710 +
  1.1711 +bool SkCanvas::quickReject(const SkPath& path) const {
  1.1712 +    return path.isEmpty() || this->quickReject(path.getBounds());
  1.1713 +}
  1.1714 +
  1.1715 +bool SkCanvas::getClipBounds(SkRect* bounds) const {
  1.1716 +    SkIRect ibounds;
  1.1717 +    if (!this->getClipDeviceBounds(&ibounds)) {
  1.1718 +        return false;
  1.1719 +    }
  1.1720 +
  1.1721 +    SkMatrix inverse;
  1.1722 +    // if we can't invert the CTM, we can't return local clip bounds
  1.1723 +    if (!fMCRec->fMatrix->invert(&inverse)) {
  1.1724 +        if (bounds) {
  1.1725 +            bounds->setEmpty();
  1.1726 +        }
  1.1727 +        return false;
  1.1728 +    }
  1.1729 +
  1.1730 +    if (NULL != bounds) {
  1.1731 +        SkRect r;
  1.1732 +        // adjust it outwards in case we are antialiasing
  1.1733 +        const int inset = 1;
  1.1734 +
  1.1735 +        r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
  1.1736 +               ibounds.fRight + inset, ibounds.fBottom + inset);
  1.1737 +        inverse.mapRect(bounds, r);
  1.1738 +    }
  1.1739 +    return true;
  1.1740 +}
  1.1741 +
  1.1742 +bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
  1.1743 +    const SkRasterClip& clip = *fMCRec->fRasterClip;
  1.1744 +    if (clip.isEmpty()) {
  1.1745 +        if (bounds) {
  1.1746 +            bounds->setEmpty();
  1.1747 +        }
  1.1748 +        return false;
  1.1749 +    }
  1.1750 +
  1.1751 +    if (NULL != bounds) {
  1.1752 +        *bounds = clip.getBounds();
  1.1753 +    }
  1.1754 +    return true;
  1.1755 +}
  1.1756 +
  1.1757 +const SkMatrix& SkCanvas::getTotalMatrix() const {
  1.1758 +    return *fMCRec->fMatrix;
  1.1759 +}
  1.1760 +
  1.1761 +#ifdef SK_SUPPORT_LEGACY_GETCLIPTYPE
  1.1762 +SkCanvas::ClipType SkCanvas::getClipType() const {
  1.1763 +    if (fMCRec->fRasterClip->isEmpty()) {
  1.1764 +        return kEmpty_ClipType;
  1.1765 +    }
  1.1766 +    if (fMCRec->fRasterClip->isRect()) {
  1.1767 +        return kRect_ClipType;
  1.1768 +    }
  1.1769 +    return kComplex_ClipType;
  1.1770 +}
  1.1771 +#endif
  1.1772 +
  1.1773 +#ifdef SK_SUPPORT_LEGACY_GETTOTALCLIP
  1.1774 +const SkRegion& SkCanvas::getTotalClip() const {
  1.1775 +    return fMCRec->fRasterClip->forceGetBW();
  1.1776 +}
  1.1777 +#endif
  1.1778 +
  1.1779 +const SkRegion& SkCanvas::internal_private_getTotalClip() const {
  1.1780 +    return fMCRec->fRasterClip->forceGetBW();
  1.1781 +}
  1.1782 +
  1.1783 +void SkCanvas::internal_private_getTotalClipAsPath(SkPath* path) const {
  1.1784 +    path->reset();
  1.1785 +
  1.1786 +    const SkRegion& rgn = fMCRec->fRasterClip->forceGetBW();
  1.1787 +    if (rgn.isEmpty()) {
  1.1788 +        return;
  1.1789 +    }
  1.1790 +    (void)rgn.getBoundaryPath(path);
  1.1791 +}
  1.1792 +
  1.1793 +GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
  1.1794 +    SkBaseDevice* dev = this->getTopDevice();
  1.1795 +    return dev ? dev->accessRenderTarget() : NULL;
  1.1796 +}
  1.1797 +
  1.1798 +SkBaseDevice* SkCanvas::createLayerDevice(const SkImageInfo& info) {
  1.1799 +    SkBaseDevice* device = this->getTopDevice();
  1.1800 +    return device ? device->createCompatibleDeviceForSaveLayer(info) : NULL;
  1.1801 +}
  1.1802 +
  1.1803 +GrContext* SkCanvas::getGrContext() {
  1.1804 +#if SK_SUPPORT_GPU
  1.1805 +    SkBaseDevice* device = this->getTopDevice();
  1.1806 +    if (NULL != device) {
  1.1807 +        GrRenderTarget* renderTarget = device->accessRenderTarget();
  1.1808 +        if (NULL != renderTarget) {
  1.1809 +            return renderTarget->getContext();
  1.1810 +        }
  1.1811 +    }
  1.1812 +#endif
  1.1813 +
  1.1814 +    return NULL;
  1.1815 +
  1.1816 +}
  1.1817 +
  1.1818 +void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
  1.1819 +                          const SkPaint& paint) {
  1.1820 +    if (outer.isEmpty()) {
  1.1821 +        return;
  1.1822 +    }
  1.1823 +    if (inner.isEmpty()) {
  1.1824 +        this->drawRRect(outer, paint);
  1.1825 +        return;
  1.1826 +    }
  1.1827 +
  1.1828 +    // We don't have this method (yet), but technically this is what we should
  1.1829 +    // be able to assert...
  1.1830 +    // SkASSERT(outer.contains(inner));
  1.1831 +    //
  1.1832 +    // For now at least check for containment of bounds
  1.1833 +    SkASSERT(outer.getBounds().contains(inner.getBounds()));
  1.1834 +
  1.1835 +    this->onDrawDRRect(outer, inner, paint);
  1.1836 +}
  1.1837 +
  1.1838 +//////////////////////////////////////////////////////////////////////////////
  1.1839 +//  These are the virtual drawing methods
  1.1840 +//////////////////////////////////////////////////////////////////////////////
  1.1841 +
  1.1842 +void SkCanvas::clear(SkColor color) {
  1.1843 +    SkDrawIter  iter(this);
  1.1844 +    this->predrawNotify();
  1.1845 +    while (iter.next()) {
  1.1846 +        iter.fDevice->clear(color);
  1.1847 +    }
  1.1848 +}
  1.1849 +
  1.1850 +void SkCanvas::drawPaint(const SkPaint& paint) {
  1.1851 +    this->internalDrawPaint(paint);
  1.1852 +}
  1.1853 +
  1.1854 +void SkCanvas::internalDrawPaint(const SkPaint& paint) {
  1.1855 +    CHECK_SHADER_NOSETCONTEXT(paint);
  1.1856 +
  1.1857 +    LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL)
  1.1858 +
  1.1859 +    while (iter.next()) {
  1.1860 +        iter.fDevice->drawPaint(iter, looper.paint());
  1.1861 +    }
  1.1862 +
  1.1863 +    LOOPER_END
  1.1864 +}
  1.1865 +
  1.1866 +void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
  1.1867 +                          const SkPaint& paint) {
  1.1868 +    if ((long)count <= 0) {
  1.1869 +        return;
  1.1870 +    }
  1.1871 +
  1.1872 +    CHECK_SHADER_NOSETCONTEXT(paint);
  1.1873 +
  1.1874 +    SkRect r, storage;
  1.1875 +    const SkRect* bounds = NULL;
  1.1876 +    if (paint.canComputeFastBounds()) {
  1.1877 +        // special-case 2 points (common for drawing a single line)
  1.1878 +        if (2 == count) {
  1.1879 +            r.set(pts[0], pts[1]);
  1.1880 +        } else {
  1.1881 +            r.set(pts, SkToInt(count));
  1.1882 +        }
  1.1883 +        bounds = &paint.computeFastStrokeBounds(r, &storage);
  1.1884 +        if (this->quickReject(*bounds)) {
  1.1885 +            return;
  1.1886 +        }
  1.1887 +    }
  1.1888 +
  1.1889 +    SkASSERT(pts != NULL);
  1.1890 +
  1.1891 +    LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
  1.1892 +
  1.1893 +    while (iter.next()) {
  1.1894 +        iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
  1.1895 +    }
  1.1896 +
  1.1897 +    LOOPER_END
  1.1898 +}
  1.1899 +
  1.1900 +void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
  1.1901 +    CHECK_SHADER_NOSETCONTEXT(paint);
  1.1902 +
  1.1903 +    SkRect storage;
  1.1904 +    const SkRect* bounds = NULL;
  1.1905 +    if (paint.canComputeFastBounds()) {
  1.1906 +        bounds = &paint.computeFastBounds(r, &storage);
  1.1907 +        if (this->quickReject(*bounds)) {
  1.1908 +            return;
  1.1909 +        }
  1.1910 +    }
  1.1911 +
  1.1912 +    LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
  1.1913 +
  1.1914 +    while (iter.next()) {
  1.1915 +        iter.fDevice->drawRect(iter, r, looper.paint());
  1.1916 +    }
  1.1917 +
  1.1918 +    LOOPER_END
  1.1919 +}
  1.1920 +
  1.1921 +void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
  1.1922 +    CHECK_SHADER_NOSETCONTEXT(paint);
  1.1923 +
  1.1924 +    SkRect storage;
  1.1925 +    const SkRect* bounds = NULL;
  1.1926 +    if (paint.canComputeFastBounds()) {
  1.1927 +        bounds = &paint.computeFastBounds(oval, &storage);
  1.1928 +        if (this->quickReject(*bounds)) {
  1.1929 +            return;
  1.1930 +        }
  1.1931 +    }
  1.1932 +
  1.1933 +    LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
  1.1934 +
  1.1935 +    while (iter.next()) {
  1.1936 +        iter.fDevice->drawOval(iter, oval, looper.paint());
  1.1937 +    }
  1.1938 +
  1.1939 +    LOOPER_END
  1.1940 +}
  1.1941 +
  1.1942 +void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
  1.1943 +    CHECK_SHADER_NOSETCONTEXT(paint);
  1.1944 +
  1.1945 +    SkRect storage;
  1.1946 +    const SkRect* bounds = NULL;
  1.1947 +    if (paint.canComputeFastBounds()) {
  1.1948 +        bounds = &paint.computeFastBounds(rrect.getBounds(), &storage);
  1.1949 +        if (this->quickReject(*bounds)) {
  1.1950 +            return;
  1.1951 +        }
  1.1952 +    }
  1.1953 +
  1.1954 +    if (rrect.isRect()) {
  1.1955 +        // call the non-virtual version
  1.1956 +        this->SkCanvas::drawRect(rrect.getBounds(), paint);
  1.1957 +        return;
  1.1958 +    } else if (rrect.isOval()) {
  1.1959 +        // call the non-virtual version
  1.1960 +        this->SkCanvas::drawOval(rrect.getBounds(), paint);
  1.1961 +        return;
  1.1962 +    }
  1.1963 +
  1.1964 +    LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
  1.1965 +
  1.1966 +    while (iter.next()) {
  1.1967 +        iter.fDevice->drawRRect(iter, rrect, looper.paint());
  1.1968 +    }
  1.1969 +
  1.1970 +    LOOPER_END
  1.1971 +}
  1.1972 +
  1.1973 +void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
  1.1974 +                            const SkPaint& paint) {
  1.1975 +    CHECK_SHADER_NOSETCONTEXT(paint);
  1.1976 +
  1.1977 +    SkRect storage;
  1.1978 +    const SkRect* bounds = NULL;
  1.1979 +    if (paint.canComputeFastBounds()) {
  1.1980 +        bounds = &paint.computeFastBounds(outer.getBounds(), &storage);
  1.1981 +        if (this->quickReject(*bounds)) {
  1.1982 +            return;
  1.1983 +        }
  1.1984 +    }
  1.1985 +
  1.1986 +    LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
  1.1987 +
  1.1988 +    while (iter.next()) {
  1.1989 +        iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
  1.1990 +    }
  1.1991 +
  1.1992 +    LOOPER_END
  1.1993 +}
  1.1994 +
  1.1995 +void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
  1.1996 +    CHECK_SHADER_NOSETCONTEXT(paint);
  1.1997 +
  1.1998 +    if (!path.isFinite()) {
  1.1999 +        return;
  1.2000 +    }
  1.2001 +
  1.2002 +    SkRect storage;
  1.2003 +    const SkRect* bounds = NULL;
  1.2004 +    if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
  1.2005 +        const SkRect& pathBounds = path.getBounds();
  1.2006 +        bounds = &paint.computeFastBounds(pathBounds, &storage);
  1.2007 +        if (this->quickReject(*bounds)) {
  1.2008 +            return;
  1.2009 +        }
  1.2010 +    }
  1.2011 +
  1.2012 +    const SkRect& r = path.getBounds();
  1.2013 +    if (r.width() <= 0 && r.height() <= 0) {
  1.2014 +        if (path.isInverseFillType()) {
  1.2015 +            this->internalDrawPaint(paint);
  1.2016 +        }
  1.2017 +        return;
  1.2018 +    }
  1.2019 +
  1.2020 +    LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
  1.2021 +
  1.2022 +    while (iter.next()) {
  1.2023 +        iter.fDevice->drawPath(iter, path, looper.paint());
  1.2024 +    }
  1.2025 +
  1.2026 +    LOOPER_END
  1.2027 +}
  1.2028 +
  1.2029 +void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
  1.2030 +                          const SkPaint* paint) {
  1.2031 +    SkDEBUGCODE(bitmap.validate();)
  1.2032 +
  1.2033 +    if (NULL == paint || paint->canComputeFastBounds()) {
  1.2034 +        SkRect bounds = {
  1.2035 +            x, y,
  1.2036 +            x + SkIntToScalar(bitmap.width()),
  1.2037 +            y + SkIntToScalar(bitmap.height())
  1.2038 +        };
  1.2039 +        if (paint) {
  1.2040 +            (void)paint->computeFastBounds(bounds, &bounds);
  1.2041 +        }
  1.2042 +        if (this->quickReject(bounds)) {
  1.2043 +            return;
  1.2044 +        }
  1.2045 +    }
  1.2046 +
  1.2047 +    SkMatrix matrix;
  1.2048 +    matrix.setTranslate(x, y);
  1.2049 +    this->internalDrawBitmap(bitmap, matrix, paint);
  1.2050 +}
  1.2051 +
  1.2052 +// this one is non-virtual, so it can be called safely by other canvas apis
  1.2053 +void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
  1.2054 +                                      const SkRect& dst, const SkPaint* paint,
  1.2055 +                                      DrawBitmapRectFlags flags) {
  1.2056 +    if (bitmap.drawsNothing() || dst.isEmpty()) {
  1.2057 +        return;
  1.2058 +    }
  1.2059 +
  1.2060 +    CHECK_LOCKCOUNT_BALANCE(bitmap);
  1.2061 +
  1.2062 +    SkRect storage;
  1.2063 +    const SkRect* bounds = &dst;
  1.2064 +    if (NULL == paint || paint->canComputeFastBounds()) {
  1.2065 +        if (paint) {
  1.2066 +            bounds = &paint->computeFastBounds(dst, &storage);
  1.2067 +        }
  1.2068 +        if (this->quickReject(*bounds)) {
  1.2069 +            return;
  1.2070 +        }
  1.2071 +    }
  1.2072 +
  1.2073 +    SkLazyPaint lazy;
  1.2074 +    if (NULL == paint) {
  1.2075 +        paint = lazy.init();
  1.2076 +    }
  1.2077 +
  1.2078 +    LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
  1.2079 +
  1.2080 +    while (iter.next()) {
  1.2081 +        iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags);
  1.2082 +    }
  1.2083 +
  1.2084 +    LOOPER_END
  1.2085 +}
  1.2086 +
  1.2087 +void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
  1.2088 +                                    const SkRect& dst, const SkPaint* paint,
  1.2089 +                                    DrawBitmapRectFlags flags) {
  1.2090 +    SkDEBUGCODE(bitmap.validate();)
  1.2091 +    this->internalDrawBitmapRect(bitmap, src, dst, paint, flags);
  1.2092 +}
  1.2093 +
  1.2094 +void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
  1.2095 +                                const SkPaint* paint) {
  1.2096 +    SkDEBUGCODE(bitmap.validate();)
  1.2097 +    this->internalDrawBitmap(bitmap, matrix, paint);
  1.2098 +}
  1.2099 +
  1.2100 +void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
  1.2101 +                                      const SkIRect& center, const SkRect& dst,
  1.2102 +                                      const SkPaint* paint) {
  1.2103 +    if (bitmap.drawsNothing()) {
  1.2104 +        return;
  1.2105 +    }
  1.2106 +    if (NULL == paint || paint->canComputeFastBounds()) {
  1.2107 +        SkRect storage;
  1.2108 +        const SkRect* bounds = &dst;
  1.2109 +        if (paint) {
  1.2110 +            bounds = &paint->computeFastBounds(dst, &storage);
  1.2111 +        }
  1.2112 +        if (this->quickReject(*bounds)) {
  1.2113 +            return;
  1.2114 +        }
  1.2115 +    }
  1.2116 +
  1.2117 +    const int32_t w = bitmap.width();
  1.2118 +    const int32_t h = bitmap.height();
  1.2119 +
  1.2120 +    SkIRect c = center;
  1.2121 +    // pin center to the bounds of the bitmap
  1.2122 +    c.fLeft = SkMax32(0, center.fLeft);
  1.2123 +    c.fTop = SkMax32(0, center.fTop);
  1.2124 +    c.fRight = SkPin32(center.fRight, c.fLeft, w);
  1.2125 +    c.fBottom = SkPin32(center.fBottom, c.fTop, h);
  1.2126 +
  1.2127 +    const SkScalar srcX[4] = {
  1.2128 +        0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w)
  1.2129 +    };
  1.2130 +    const SkScalar srcY[4] = {
  1.2131 +        0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h)
  1.2132 +    };
  1.2133 +    SkScalar dstX[4] = {
  1.2134 +        dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
  1.2135 +        dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
  1.2136 +    };
  1.2137 +    SkScalar dstY[4] = {
  1.2138 +        dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
  1.2139 +        dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
  1.2140 +    };
  1.2141 +
  1.2142 +    if (dstX[1] > dstX[2]) {
  1.2143 +        dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
  1.2144 +        dstX[2] = dstX[1];
  1.2145 +    }
  1.2146 +
  1.2147 +    if (dstY[1] > dstY[2]) {
  1.2148 +        dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
  1.2149 +        dstY[2] = dstY[1];
  1.2150 +    }
  1.2151 +
  1.2152 +    for (int y = 0; y < 3; y++) {
  1.2153 +        SkRect s, d;
  1.2154 +
  1.2155 +        s.fTop = srcY[y];
  1.2156 +        s.fBottom = srcY[y+1];
  1.2157 +        d.fTop = dstY[y];
  1.2158 +        d.fBottom = dstY[y+1];
  1.2159 +        for (int x = 0; x < 3; x++) {
  1.2160 +            s.fLeft = srcX[x];
  1.2161 +            s.fRight = srcX[x+1];
  1.2162 +            d.fLeft = dstX[x];
  1.2163 +            d.fRight = dstX[x+1];
  1.2164 +            this->internalDrawBitmapRect(bitmap, &s, d, paint,
  1.2165 +                                         kNone_DrawBitmapRectFlag);
  1.2166 +        }
  1.2167 +    }
  1.2168 +}
  1.2169 +
  1.2170 +void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
  1.2171 +                              const SkRect& dst, const SkPaint* paint) {
  1.2172 +    SkDEBUGCODE(bitmap.validate();)
  1.2173 +
  1.2174 +    // Need a device entry-point, so gpu can use a mesh
  1.2175 +    this->internalDrawBitmapNine(bitmap, center, dst, paint);
  1.2176 +}
  1.2177 +
  1.2178 +class SkDeviceFilteredPaint {
  1.2179 +public:
  1.2180 +    SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
  1.2181 +        SkBaseDevice::TextFlags flags;
  1.2182 +        if (device->filterTextFlags(paint, &flags)) {
  1.2183 +            SkPaint* newPaint = fLazy.set(paint);
  1.2184 +            newPaint->setFlags(flags.fFlags);
  1.2185 +            newPaint->setHinting(flags.fHinting);
  1.2186 +            fPaint = newPaint;
  1.2187 +        } else {
  1.2188 +            fPaint = &paint;
  1.2189 +        }
  1.2190 +    }
  1.2191 +
  1.2192 +    const SkPaint& paint() const { return *fPaint; }
  1.2193 +
  1.2194 +private:
  1.2195 +    const SkPaint*  fPaint;
  1.2196 +    SkLazyPaint     fLazy;
  1.2197 +};
  1.2198 +
  1.2199 +void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
  1.2200 +                        const SkRect& r, SkScalar textSize) {
  1.2201 +    if (paint.getStyle() == SkPaint::kFill_Style) {
  1.2202 +        draw.fDevice->drawRect(draw, r, paint);
  1.2203 +    } else {
  1.2204 +        SkPaint p(paint);
  1.2205 +        p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
  1.2206 +        draw.fDevice->drawRect(draw, r, p);
  1.2207 +    }
  1.2208 +}
  1.2209 +
  1.2210 +void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
  1.2211 +                                   const char text[], size_t byteLength,
  1.2212 +                                   SkScalar x, SkScalar y) {
  1.2213 +    SkASSERT(byteLength == 0 || text != NULL);
  1.2214 +
  1.2215 +    // nothing to draw
  1.2216 +    if (text == NULL || byteLength == 0 ||
  1.2217 +        draw.fClip->isEmpty() ||
  1.2218 +        (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
  1.2219 +        return;
  1.2220 +    }
  1.2221 +
  1.2222 +    SkScalar    width = 0;
  1.2223 +    SkPoint     start;
  1.2224 +
  1.2225 +    start.set(0, 0);    // to avoid warning
  1.2226 +    if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
  1.2227 +                            SkPaint::kStrikeThruText_Flag)) {
  1.2228 +        width = paint.measureText(text, byteLength);
  1.2229 +
  1.2230 +        SkScalar offsetX = 0;
  1.2231 +        if (paint.getTextAlign() == SkPaint::kCenter_Align) {
  1.2232 +            offsetX = SkScalarHalf(width);
  1.2233 +        } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
  1.2234 +            offsetX = width;
  1.2235 +        }
  1.2236 +        start.set(x - offsetX, y);
  1.2237 +    }
  1.2238 +
  1.2239 +    if (0 == width) {
  1.2240 +        return;
  1.2241 +    }
  1.2242 +
  1.2243 +    uint32_t flags = paint.getFlags();
  1.2244 +
  1.2245 +    if (flags & (SkPaint::kUnderlineText_Flag |
  1.2246 +                 SkPaint::kStrikeThruText_Flag)) {
  1.2247 +        SkScalar textSize = paint.getTextSize();
  1.2248 +        SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
  1.2249 +        SkRect   r;
  1.2250 +
  1.2251 +        r.fLeft = start.fX;
  1.2252 +        r.fRight = start.fX + width;
  1.2253 +
  1.2254 +        if (flags & SkPaint::kUnderlineText_Flag) {
  1.2255 +            SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
  1.2256 +                                             start.fY);
  1.2257 +            r.fTop = offset;
  1.2258 +            r.fBottom = offset + height;
  1.2259 +            DrawRect(draw, paint, r, textSize);
  1.2260 +        }
  1.2261 +        if (flags & SkPaint::kStrikeThruText_Flag) {
  1.2262 +            SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
  1.2263 +                                             start.fY);
  1.2264 +            r.fTop = offset;
  1.2265 +            r.fBottom = offset + height;
  1.2266 +            DrawRect(draw, paint, r, textSize);
  1.2267 +        }
  1.2268 +    }
  1.2269 +}
  1.2270 +
  1.2271 +void SkCanvas::drawText(const void* text, size_t byteLength,
  1.2272 +                        SkScalar x, SkScalar y, const SkPaint& paint) {
  1.2273 +    CHECK_SHADER_NOSETCONTEXT(paint);
  1.2274 +
  1.2275 +    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
  1.2276 +
  1.2277 +    while (iter.next()) {
  1.2278 +        SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
  1.2279 +        iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
  1.2280 +        DrawTextDecorations(iter, dfp.paint(),
  1.2281 +                            static_cast<const char*>(text), byteLength, x, y);
  1.2282 +    }
  1.2283 +
  1.2284 +    LOOPER_END
  1.2285 +}
  1.2286 +
  1.2287 +void SkCanvas::drawPosText(const void* text, size_t byteLength,
  1.2288 +                           const SkPoint pos[], const SkPaint& paint) {
  1.2289 +    CHECK_SHADER_NOSETCONTEXT(paint);
  1.2290 +
  1.2291 +    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
  1.2292 +
  1.2293 +    while (iter.next()) {
  1.2294 +        SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
  1.2295 +        iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2,
  1.2296 +                                  dfp.paint());
  1.2297 +    }
  1.2298 +
  1.2299 +    LOOPER_END
  1.2300 +}
  1.2301 +
  1.2302 +void SkCanvas::drawPosTextH(const void* text, size_t byteLength,
  1.2303 +                            const SkScalar xpos[], SkScalar constY,
  1.2304 +                            const SkPaint& paint) {
  1.2305 +    CHECK_SHADER_NOSETCONTEXT(paint);
  1.2306 +
  1.2307 +    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
  1.2308 +
  1.2309 +    while (iter.next()) {
  1.2310 +        SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
  1.2311 +        iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1,
  1.2312 +                                  dfp.paint());
  1.2313 +    }
  1.2314 +
  1.2315 +    LOOPER_END
  1.2316 +}
  1.2317 +
  1.2318 +void SkCanvas::drawTextOnPath(const void* text, size_t byteLength,
  1.2319 +                              const SkPath& path, const SkMatrix* matrix,
  1.2320 +                              const SkPaint& paint) {
  1.2321 +    CHECK_SHADER_NOSETCONTEXT(paint);
  1.2322 +
  1.2323 +    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
  1.2324 +
  1.2325 +    while (iter.next()) {
  1.2326 +        iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
  1.2327 +                                     matrix, looper.paint());
  1.2328 +    }
  1.2329 +
  1.2330 +    LOOPER_END
  1.2331 +}
  1.2332 +
  1.2333 +void SkCanvas::drawVertices(VertexMode vmode, int vertexCount,
  1.2334 +                            const SkPoint verts[], const SkPoint texs[],
  1.2335 +                            const SkColor colors[], SkXfermode* xmode,
  1.2336 +                            const uint16_t indices[], int indexCount,
  1.2337 +                            const SkPaint& paint) {
  1.2338 +    CHECK_SHADER_NOSETCONTEXT(paint);
  1.2339 +
  1.2340 +    LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
  1.2341 +
  1.2342 +    while (iter.next()) {
  1.2343 +        iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
  1.2344 +                                   colors, xmode, indices, indexCount,
  1.2345 +                                   looper.paint());
  1.2346 +    }
  1.2347 +
  1.2348 +    LOOPER_END
  1.2349 +}
  1.2350 +
  1.2351 +//////////////////////////////////////////////////////////////////////////////
  1.2352 +// These methods are NOT virtual, and therefore must call back into virtual
  1.2353 +// methods, rather than actually drawing themselves.
  1.2354 +//////////////////////////////////////////////////////////////////////////////
  1.2355 +
  1.2356 +void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
  1.2357 +                        SkXfermode::Mode mode) {
  1.2358 +    SkPaint paint;
  1.2359 +
  1.2360 +    paint.setARGB(a, r, g, b);
  1.2361 +    if (SkXfermode::kSrcOver_Mode != mode) {
  1.2362 +        paint.setXfermodeMode(mode);
  1.2363 +    }
  1.2364 +    this->drawPaint(paint);
  1.2365 +}
  1.2366 +
  1.2367 +void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
  1.2368 +    SkPaint paint;
  1.2369 +
  1.2370 +    paint.setColor(c);
  1.2371 +    if (SkXfermode::kSrcOver_Mode != mode) {
  1.2372 +        paint.setXfermodeMode(mode);
  1.2373 +    }
  1.2374 +    this->drawPaint(paint);
  1.2375 +}
  1.2376 +
  1.2377 +void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
  1.2378 +    SkPoint pt;
  1.2379 +
  1.2380 +    pt.set(x, y);
  1.2381 +    this->drawPoints(kPoints_PointMode, 1, &pt, paint);
  1.2382 +}
  1.2383 +
  1.2384 +void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
  1.2385 +    SkPoint pt;
  1.2386 +    SkPaint paint;
  1.2387 +
  1.2388 +    pt.set(x, y);
  1.2389 +    paint.setColor(color);
  1.2390 +    this->drawPoints(kPoints_PointMode, 1, &pt, paint);
  1.2391 +}
  1.2392 +
  1.2393 +void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
  1.2394 +                        const SkPaint& paint) {
  1.2395 +    SkPoint pts[2];
  1.2396 +
  1.2397 +    pts[0].set(x0, y0);
  1.2398 +    pts[1].set(x1, y1);
  1.2399 +    this->drawPoints(kLines_PointMode, 2, pts, paint);
  1.2400 +}
  1.2401 +
  1.2402 +void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
  1.2403 +                              SkScalar right, SkScalar bottom,
  1.2404 +                              const SkPaint& paint) {
  1.2405 +    SkRect  r;
  1.2406 +
  1.2407 +    r.set(left, top, right, bottom);
  1.2408 +    this->drawRect(r, paint);
  1.2409 +}
  1.2410 +
  1.2411 +void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
  1.2412 +                          const SkPaint& paint) {
  1.2413 +    if (radius < 0) {
  1.2414 +        radius = 0;
  1.2415 +    }
  1.2416 +
  1.2417 +    SkRect  r;
  1.2418 +    r.set(cx - radius, cy - radius, cx + radius, cy + radius);
  1.2419 +    this->drawOval(r, paint);
  1.2420 +}
  1.2421 +
  1.2422 +void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
  1.2423 +                             const SkPaint& paint) {
  1.2424 +    if (rx > 0 && ry > 0) {
  1.2425 +        if (paint.canComputeFastBounds()) {
  1.2426 +            SkRect storage;
  1.2427 +            if (this->quickReject(paint.computeFastBounds(r, &storage))) {
  1.2428 +                return;
  1.2429 +            }
  1.2430 +        }
  1.2431 +        SkRRect rrect;
  1.2432 +        rrect.setRectXY(r, rx, ry);
  1.2433 +        this->drawRRect(rrect, paint);
  1.2434 +    } else {
  1.2435 +        this->drawRect(r, paint);
  1.2436 +    }
  1.2437 +}
  1.2438 +
  1.2439 +void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
  1.2440 +                       SkScalar sweepAngle, bool useCenter,
  1.2441 +                       const SkPaint& paint) {
  1.2442 +    if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
  1.2443 +        this->drawOval(oval, paint);
  1.2444 +    } else {
  1.2445 +        SkPath  path;
  1.2446 +        if (useCenter) {
  1.2447 +            path.moveTo(oval.centerX(), oval.centerY());
  1.2448 +        }
  1.2449 +        path.arcTo(oval, startAngle, sweepAngle, !useCenter);
  1.2450 +        if (useCenter) {
  1.2451 +            path.close();
  1.2452 +        }
  1.2453 +        this->drawPath(path, paint);
  1.2454 +    }
  1.2455 +}
  1.2456 +
  1.2457 +void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
  1.2458 +                                const SkPath& path, SkScalar hOffset,
  1.2459 +                                SkScalar vOffset, const SkPaint& paint) {
  1.2460 +    SkMatrix    matrix;
  1.2461 +
  1.2462 +    matrix.setTranslate(hOffset, vOffset);
  1.2463 +    this->drawTextOnPath(text, byteLength, path, &matrix, paint);
  1.2464 +}
  1.2465 +
  1.2466 +///////////////////////////////////////////////////////////////////////////////
  1.2467 +void SkCanvas::EXPERIMENTAL_optimize(SkPicture* picture) {
  1.2468 +    SkBaseDevice* device = this->getDevice();
  1.2469 +    if (NULL != device) {
  1.2470 +        device->EXPERIMENTAL_optimize(picture);
  1.2471 +    }
  1.2472 +}
  1.2473 +
  1.2474 +void SkCanvas::drawPicture(SkPicture& picture) {
  1.2475 +    SkBaseDevice* device = this->getTopDevice();
  1.2476 +    if (NULL != device) {
  1.2477 +        // Canvas has to first give the device the opportunity to render
  1.2478 +        // the picture itself.
  1.2479 +        if (device->EXPERIMENTAL_drawPicture(picture)) {
  1.2480 +            return; // the device has rendered the entire picture
  1.2481 +        }
  1.2482 +    }
  1.2483 +
  1.2484 +    picture.draw(this);
  1.2485 +}
  1.2486 +
  1.2487 +///////////////////////////////////////////////////////////////////////////////
  1.2488 +///////////////////////////////////////////////////////////////////////////////
  1.2489 +
  1.2490 +SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
  1.2491 +    SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
  1.2492 +
  1.2493 +    SkASSERT(canvas);
  1.2494 +
  1.2495 +    fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
  1.2496 +    fDone = !fImpl->next();
  1.2497 +}
  1.2498 +
  1.2499 +SkCanvas::LayerIter::~LayerIter() {
  1.2500 +    fImpl->~SkDrawIter();
  1.2501 +}
  1.2502 +
  1.2503 +void SkCanvas::LayerIter::next() {
  1.2504 +    fDone = !fImpl->next();
  1.2505 +}
  1.2506 +
  1.2507 +SkBaseDevice* SkCanvas::LayerIter::device() const {
  1.2508 +    return fImpl->getDevice();
  1.2509 +}
  1.2510 +
  1.2511 +const SkMatrix& SkCanvas::LayerIter::matrix() const {
  1.2512 +    return fImpl->getMatrix();
  1.2513 +}
  1.2514 +
  1.2515 +const SkPaint& SkCanvas::LayerIter::paint() const {
  1.2516 +    const SkPaint* paint = fImpl->getPaint();
  1.2517 +    if (NULL == paint) {
  1.2518 +        paint = &fDefaultPaint;
  1.2519 +    }
  1.2520 +    return *paint;
  1.2521 +}
  1.2522 +
  1.2523 +const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
  1.2524 +int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
  1.2525 +int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
  1.2526 +
  1.2527 +///////////////////////////////////////////////////////////////////////////////
  1.2528 +
  1.2529 +SkCanvas::ClipVisitor::~ClipVisitor() { }
  1.2530 +
  1.2531 +///////////////////////////////////////////////////////////////////////////////
  1.2532 +
  1.2533 +static bool supported_for_raster_canvas(const SkImageInfo& info) {
  1.2534 +    switch (info.alphaType()) {
  1.2535 +        case kPremul_SkAlphaType:
  1.2536 +        case kOpaque_SkAlphaType:
  1.2537 +            break;
  1.2538 +        default:
  1.2539 +            return false;
  1.2540 +    }
  1.2541 +
  1.2542 +    switch (info.colorType()) {
  1.2543 +        case kAlpha_8_SkColorType:
  1.2544 +        case kRGB_565_SkColorType:
  1.2545 +        case kPMColor_SkColorType:
  1.2546 +            break;
  1.2547 +        default:
  1.2548 +            return false;
  1.2549 +    }
  1.2550 +
  1.2551 +    return true;
  1.2552 +}
  1.2553 +
  1.2554 +SkCanvas* SkCanvas::NewRaster(const SkImageInfo& info) {
  1.2555 +    if (!supported_for_raster_canvas(info)) {
  1.2556 +        return NULL;
  1.2557 +    }
  1.2558 +
  1.2559 +    SkBitmap bitmap;
  1.2560 +    if (!bitmap.allocPixels(info)) {
  1.2561 +        return NULL;
  1.2562 +    }
  1.2563 +
  1.2564 +    // should this functionality be moved into allocPixels()?
  1.2565 +    if (!bitmap.info().isOpaque()) {
  1.2566 +        bitmap.eraseColor(0);
  1.2567 +    }
  1.2568 +    return SkNEW_ARGS(SkCanvas, (bitmap));
  1.2569 +}
  1.2570 +
  1.2571 +SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
  1.2572 +    if (!supported_for_raster_canvas(info)) {
  1.2573 +        return NULL;
  1.2574 +    }
  1.2575 +
  1.2576 +    SkBitmap bitmap;
  1.2577 +    if (!bitmap.installPixels(info, pixels, rowBytes)) {
  1.2578 +        return NULL;
  1.2579 +    }
  1.2580 +
  1.2581 +    // should this functionality be moved into allocPixels()?
  1.2582 +    if (!bitmap.info().isOpaque()) {
  1.2583 +        bitmap.eraseColor(0);
  1.2584 +    }
  1.2585 +    return SkNEW_ARGS(SkCanvas, (bitmap));
  1.2586 +}

mercurial