Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / core / SkCanvas.cpp
index 7e2609b..afd7fbe 100644 (file)
@@ -5,7 +5,6 @@
  * found in the LICENSE file.
  */
 
-
 #include "SkCanvas.h"
 #include "SkCanvasPriv.h"
 #include "SkBitmapDevice.h"
@@ -13,6 +12,7 @@
 #include "SkDraw.h"
 #include "SkDrawFilter.h"
 #include "SkDrawLooper.h"
+#include "SkImage.h"
 #include "SkMetaData.h"
 #include "SkPathOps.h"
 #include "SkPatchUtils.h"
@@ -22,6 +22,7 @@
 #include "SkSmallAllocator.h"
 #include "SkSurface_Base.h"
 #include "SkTemplates.h"
+#include "SkTextBlob.h"
 #include "SkTextFormatParams.h"
 #include "SkTLazy.h"
 #include "SkUtils.h"
@@ -66,6 +67,19 @@ void SkCanvas::predrawNotify() {
 
 ///////////////////////////////////////////////////////////////////////////////
 
+static uint32_t filter_paint_flags(const SkSurfaceProps& props, uint32_t flags) {
+    const uint32_t propFlags = props.flags();
+    if (propFlags & SkSurfaceProps::kDisallowDither_Flag) {
+        flags &= ~SkPaint::kDither_Flag;
+    }
+    if (propFlags & SkSurfaceProps::kDisallowAntiAlias_Flag) {
+        flags &= ~SkPaint::kAntiAlias_Flag;
+    }
+    return flags;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
 /*  This is the record we keep for each SkBaseDevice that the user installs.
     The clip/matrix/proc are fields that reflect the top of the save/restore
     stack. Whenever the canvas changes, it marks a dirty flag, and then before
@@ -80,8 +94,11 @@ struct DeviceCM {
     const SkMatrix*     fMatrix;
     SkPaint*            fPaint; // may be null (in the future)
 
-    DeviceCM(SkBaseDevice* device, int x, int y, const SkPaint* paint, SkCanvas* canvas)
-            : fNext(NULL) {
+    DeviceCM(SkBaseDevice* device, int x, int y, const SkPaint* paint, SkCanvas* canvas,
+             bool conservativeRasterClip)
+        : fNext(NULL)
+        , fClip(conservativeRasterClip)
+    {
         if (NULL != device) {
             device->ref();
             device->onAttachToCanvas(canvas);
@@ -91,7 +108,7 @@ struct DeviceCM {
     }
 
     ~DeviceCM() {
-        if (NULL != fDevice) {
+        if (fDevice) {
             fDevice->onDetachFromCanvas();
             fDevice->unref();
         }
@@ -150,11 +167,10 @@ private:
 */
 class SkCanvas::MCRec {
 public:
-    SkMatrix        fMatrix;
     SkRasterClip    fRasterClip;
+    SkMatrix        fMatrix;
     SkDrawFilter*   fFilter;    // the current filter (or null)
-
-    DeviceCM*   fLayer;
+    DeviceCM*       fLayer;
     /*  If there are any layers in the stack, this points to the top-most
         one that is at or below this level in the stack (so we know what
         bitmap/device to draw into from this level. This value is NOT
@@ -163,21 +179,20 @@ public:
     */
     DeviceCM*   fTopLayer;
 
-    MCRec(const MCRec* prev) {
-        if (NULL != prev) {
-            fMatrix = prev->fMatrix;
-            fRasterClip = prev->fRasterClip;
+    MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
+        fMatrix.reset();
+        fFilter     = NULL;
+        fLayer      = NULL;
+        fTopLayer   = NULL;
 
-            fFilter = prev->fFilter;
-            SkSafeRef(fFilter);
-
-            fTopLayer = prev->fTopLayer;
-        } else {   // no prev
-            fMatrix.reset();
-            fFilter     = NULL;
-            fTopLayer   = NULL;
-        }
+        // don't bother initializing fNext
+        inc_rec();
+    }
+    MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip) {
+        fMatrix = prev.fMatrix;
+        fFilter = SkSafeRef(prev.fFilter);
         fLayer = NULL;
+        fTopLayer = prev.fTopLayer;
 
         // don't bother initializing fNext
         inc_rec();
@@ -248,12 +263,12 @@ private:
 
 class AutoDrawLooper {
 public:
-    AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint,
+    AutoDrawLooper(SkCanvas* canvas, const SkSurfaceProps& props, const SkPaint& paint,
                    bool skipLayerForImageFilter = false,
                    const SkRect* bounds = NULL) : fOrigPaint(paint) {
         fCanvas = canvas;
         fFilter = canvas->getDrawFilter();
-        fPaint = NULL;
+        fPaint = &fOrigPaint;
         fSaveCount = canvas->getSaveCount();
         fDoClearImageFilter = false;
         fDone = false;
@@ -278,6 +293,15 @@ public:
             // can we be marked as simple?
             fIsSimple = !fFilter && !fDoClearImageFilter;
         }
+
+        uint32_t oldFlags = paint.getFlags();
+        fNewPaintFlags = filter_paint_flags(props, oldFlags);
+        if (fIsSimple && (fNewPaintFlags != oldFlags)) {
+            SkPaint* paint = fLazyPaint.set(fOrigPaint);
+            paint->setFlags(fNewPaintFlags);
+            fPaint = paint;
+            // if we're not simple, doNext() will take care of calling setFlags()
+        }
     }
 
     ~AutoDrawLooper() {
@@ -297,7 +321,6 @@ public:
             return false;
         } else if (fIsSimple) {
             fDone = true;
-            fPaint = &fOrigPaint;
             return !fPaint->nothingToDraw();
         } else {
             return this->doNext(drawType);
@@ -311,6 +334,7 @@ private:
     SkDrawFilter*   fFilter;
     const SkPaint*  fPaint;
     int             fSaveCount;
+    uint32_t        fNewPaintFlags;
     bool            fDoClearImageFilter;
     bool            fDone;
     bool            fIsSimple;
@@ -326,6 +350,7 @@ bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
     SkASSERT(fLooperContext || fFilter || fDoClearImageFilter);
 
     SkPaint* paint = fLazyPaint.set(fOrigPaint);
+    paint->setFlags(fNewPaintFlags);
 
     if (fDoClearImageFilter) {
         paint->setImageFilter(NULL);
@@ -360,19 +385,17 @@ bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
     return true;
 }
 
-#include "SkColorPriv.h"
-
 ////////// macros to place around the internal draw calls //////////////////
 
 #define LOOPER_BEGIN_DRAWDEVICE(paint, type)                        \
     this->predrawNotify();                                          \
-    AutoDrawLooper  looper(this, paint, true);                      \
+    AutoDrawLooper  looper(this, fProps, paint, true);              \
     while (looper.next(type)) {                                     \
         SkDrawIter          iter(this);
 
 #define LOOPER_BEGIN(paint, type, bounds)                           \
     this->predrawNotify();                                          \
-    AutoDrawLooper  looper(this, paint, false, bounds);             \
+    AutoDrawLooper  looper(this, fProps, paint, false, bounds);     \
     while (looper.next(type)) {                                     \
         SkDrawIter          iter(this);
 
@@ -380,59 +403,119 @@ bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
 
 ////////////////////////////////////////////////////////////////////////////
 
-SkBaseDevice* SkCanvas::init(SkBaseDevice* device) {
+void SkCanvas::setupDevice(SkBaseDevice* device) {
+    device->setPixelGeometry(fProps.pixelGeometry());
+}
+
+SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
+    fConservativeRasterClip = SkToBool(flags & kConservativeRasterClip_InitFlag);
     fCachedLocalClipBounds.setEmpty();
     fCachedLocalClipBoundsDirty = true;
     fAllowSoftClip = true;
     fAllowSimplifyClip = false;
-    fDeviceCMDirty = false;
+    fDeviceCMDirty = true;
     fSaveLayerCount = 0;
     fCullCount = 0;
     fMetaData = NULL;
 
     fMCRec = (MCRec*)fMCStack.push_back();
-    new (fMCRec) MCRec(NULL);
+    new (fMCRec) MCRec(fConservativeRasterClip);
 
-    fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL, NULL));
+    fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL, NULL, fConservativeRasterClip));
     fMCRec->fTopLayer = fMCRec->fLayer;
 
     fSurfaceBase = NULL;
 
-    return this->setRootDevice(device);
+    if (device) {
+        this->setupDevice(device);
+        if (device->forceConservativeRasterClip()) {
+            fConservativeRasterClip = true;
+        }
+        device->onAttachToCanvas(this);
+        fMCRec->fLayer->fDevice = SkRef(device);
+        fMCRec->fRasterClip.setRect(SkIRect::MakeWH(device->width(), device->height()));
+    }
+    return device;
 }
 
 SkCanvas::SkCanvas()
     : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
+    , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
 {
     inc_canvas();
 
-    this->init(NULL);
+    this->init(NULL, kDefault_InitFlags);
 }
 
+static SkBitmap make_nopixels(int width, int height) {
+    SkBitmap bitmap;
+    bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
+    return bitmap;
+}
+
+class SkNoPixelsBitmapDevice : public SkBitmapDevice {
+public:
+    SkNoPixelsBitmapDevice(int width, int height) : INHERITED(make_nopixels(width, height)) {}
+
+private:
+
+    typedef SkBitmapDevice INHERITED;
+};
+
 SkCanvas::SkCanvas(int width, int height)
     : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
+    , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
 {
     inc_canvas();
 
-    SkBitmap bitmap;
-    bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
-    this->init(SkNEW_ARGS(SkBitmapDevice, (bitmap)))->unref();
+    this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice, (width, height)), kDefault_InitFlags)->unref();
+}
+
+SkCanvas::SkCanvas(int width, int height, InitFlags flags)
+    : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
+    , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
+{
+    inc_canvas();
+
+    this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice, (width, height)), flags)->unref();
+}
+
+SkCanvas::SkCanvas(SkBaseDevice* device, const SkSurfaceProps* props, InitFlags flags)
+    : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
+    , fProps(SkSurfacePropsCopyOrDefault(props))
+{
+    inc_canvas();
+
+    this->init(device, flags);
 }
 
 SkCanvas::SkCanvas(SkBaseDevice* device)
     : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
+    , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
+{
+    inc_canvas();
+
+    this->init(device, kDefault_InitFlags);
+}
+
+SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
+    : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
+    , fProps(props)
 {
     inc_canvas();
 
-    this->init(device);
+    SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap)));
+    this->init(device, kDefault_InitFlags);
 }
 
 SkCanvas::SkCanvas(const SkBitmap& bitmap)
     : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
+    , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
 {
     inc_canvas();
 
-    this->init(SkNEW_ARGS(SkBitmapDevice, (bitmap)))->unref();
+    SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap)));
+    this->init(device, kDefault_InitFlags);
 }
 
 SkCanvas::~SkCanvas() {
@@ -523,6 +606,7 @@ SkBaseDevice* SkCanvas::setRootDevice(SkBaseDevice* device) {
 
     SkRefCnt_SafeAssign(rec->fLayer->fDevice, device);
     rootDevice = device;
+    this->setupDevice(device);
 
     fDeviceCMDirty = true;
 
@@ -562,7 +646,7 @@ bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
 
     bool weAllocated = false;
     if (NULL == bitmap->pixelRef()) {
-        if (!bitmap->allocPixels()) {
+        if (!bitmap->tryAllocPixels()) {
             return false;
         }
         weAllocated = true;
@@ -588,7 +672,7 @@ bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
         return false;
     }
 
-    if (!bitmap->allocN32Pixels(r.width(), r.height())) {
+    if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
         // bitmap will already be reset.
         return false;
     }
@@ -625,10 +709,8 @@ bool SkCanvas::readPixels(const SkImageInfo& origInfo, void* dstP, size_t rowByt
         return false;
     }
 
-    SkImageInfo info = origInfo;
     // the intersect may have shrunk info's logical size
-    info.fWidth = srcR.width();
-    info.fHeight = srcR.height();
+    const SkImageInfo info = origInfo.makeWH(srcR.width(), srcR.height());
 
     // if x or y are negative, then we have to adjust pixels
     if (x > 0) {
@@ -680,10 +762,8 @@ bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size
         return false;
     }
 
-    SkImageInfo info = origInfo;
     // the intersect may have shrunk info's logical size
-    info.fWidth = target.width();
-    info.fHeight = target.height();
+    const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
 
     // if x or y are negative, then we have to adjust pixels
     if (x > 0) {
@@ -732,7 +812,7 @@ int SkCanvas::internalSave() {
     int saveCount = this->getSaveCount(); // record this before the actual save
 
     MCRec* newTop = (MCRec*)fMCStack.push_back();
-    new (newTop) MCRec(fMCRec);    // balanced in restore()
+    new (newTop) MCRec(*fMCRec);    // balanced in restore()
     fMCRec = newTop;
 
     fClipStack.save();
@@ -767,7 +847,7 @@ bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
         op = SkRegion::kReplace_Op;
     }
     SkIRect ir;
-    if (NULL != bounds) {
+    if (bounds) {
         SkRect r;
 
         this->getTotalMatrix().mapRect(&r, *bounds);
@@ -862,9 +942,11 @@ int SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, Save
         SkDebugf("Unable to create device for layer.");
         return count;
     }
+    this->setupDevice(device);
 
     device->setOrigin(ir.fLeft, ir.fTop);
-    DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint, this));
+    DeviceCM* layer = SkNEW_ARGS(DeviceCM,
+                                 (device, ir.fLeft, ir.fTop, paint, this, fConservativeRasterClip));
     device->unref();
 
     layer->fNext = fMCRec->fTopLayer;
@@ -921,7 +1003,7 @@ void SkCanvas::internalRestore() {
         since if we're being recorded, we don't want to record this (the
         recorder will have already recorded the restore).
     */
-    if (NULL != layer) {
+    if (layer) {
         if (layer->fNext) {
             const SkIPoint& origin = layer->fDevice->getOrigin();
             this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
@@ -956,13 +1038,16 @@ bool SkCanvas::isDrawingToLayer() const {
     return fSaveLayerCount > 0;
 }
 
-SkSurface* SkCanvas::newSurface(const SkImageInfo& info) {
-    return this->onNewSurface(info);
+SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
+    if (NULL == props) {
+        props = &fProps;
+    }
+    return this->onNewSurface(info, *props);
 }
 
-SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info) {
+SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
     SkBaseDevice* dev = this->getDevice();
-    return dev ? dev->newSurface(info) : NULL;
+    return dev ? dev->newSurface(info, props) : NULL;
 }
 
 SkImageInfo SkCanvas::imageInfo() const {
@@ -1000,7 +1085,7 @@ SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
     fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
     if (NULL == fAddr) {
         fInfo = canvas->imageInfo();
-        if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.allocPixels(fInfo)) {
+        if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.tryAllocPixels(fInfo)) {
             return; // failure, fAddr is NULL
         }
         if (!canvas->readPixels(&fBitmap, 0, 0)) {
@@ -1284,7 +1369,7 @@ void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edg
 
         fMCRec->fMatrix.mapRect(&r, rect);
         fClipStack.clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle);
-        fMCRec->fRasterClip.op(r, op, kSoft_ClipEdgeStyle == edgeStyle);
+        fMCRec->fRasterClip.op(r, this->getBaseLayerSize(), op, kSoft_ClipEdgeStyle == edgeStyle);
     } else {
         // since we're rotated or some such thing, we convert the rect to a path
         // and clip against that, since it can handle any matrix. However, to
@@ -1297,39 +1382,9 @@ void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edg
     }
 }
 
-static void clip_path_helper(const SkCanvas* canvas, SkRasterClip* currClip,
-                             const SkPath& devPath, SkRegion::Op op, bool doAA) {
-    // base is used to limit the size (and therefore memory allocation) of the
-    // region that results from scan converting devPath.
-    SkRegion base;
-
-    if (SkRegion::kIntersect_Op == op) {
-        // since we are intersect, we can do better (tighter) with currRgn's
-        // bounds, than just using the device. However, if currRgn is complex,
-        // our region blitter may hork, so we do that case in two steps.
-        if (currClip->isRect()) {
-            // FIXME: we should also be able to do this when currClip->isBW(),
-            // but relaxing the test above triggers GM asserts in
-            // SkRgnBuilder::blitH(). We need to investigate what's going on.
-            currClip->setPath(devPath, currClip->bwRgn(), doAA);
-        } else {
-            base.setRect(currClip->getBounds());
-            SkRasterClip clip;
-            clip.setPath(devPath, base, doAA);
-            currClip->op(clip, op);
-        }
-    } else {
-        const SkISize size = canvas->getBaseLayerSize();
-        base.setRect(0, 0, size.width(), size.height());
-
-        if (SkRegion::kReplace_Op == op) {
-            currClip->setPath(devPath, base, doAA);
-        } else {
-            SkRasterClip clip;
-            clip.setPath(devPath, base, doAA);
-            currClip->op(clip, op);
-        }
-    }
+static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPath& devPath,
+                            SkRegion::Op op, bool doAA) {
+    rc->op(devPath, canvas->getBaseLayerSize(), op, doAA);
 }
 
 void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
@@ -1357,7 +1412,7 @@ void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle
         SkPath devPath;
         devPath.addRRect(transformedRRect);
 
-        clip_path_helper(this, &fMCRec->fRasterClip, devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
+        rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
         return;
     }
 
@@ -1446,83 +1501,7 @@ void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edg
         op = SkRegion::kReplace_Op;
     }
 
-    clip_path_helper(this, &fMCRec->fRasterClip, devPath, op, edgeStyle);
-}
-
-void SkCanvas::updateClipConservativelyUsingBounds(const SkRect& bounds, SkRegion::Op op,
-                                                   bool inverseFilled) {
-    // This is for updating the clip conservatively using only bounds
-    // information.
-    // Contract:
-    //    The current clip must contain the true clip. The true
-    //    clip is the clip that would have normally been computed
-    //    by calls to clipPath and clipRRect
-    // Objective:
-    //    Keep the current clip as small as possible without
-    //    breaking the contract, using only clip bounding rectangles
-    //    (for performance).
-
-    // N.B.: This *never* calls back through a virtual on canvas, so subclasses
-    // don't have to worry about getting caught in a loop. Thus anywhere
-    // we call a virtual method, we explicitly prefix it with
-    // SkCanvas:: to be sure to call the base-class.
-
-    if (inverseFilled) {
-        switch (op) {
-            case SkRegion::kIntersect_Op:
-            case SkRegion::kDifference_Op:
-                // These ops can only shrink the current clip. So leaving
-                // the clip unchanged conservatively respects the contract.
-                break;
-            case SkRegion::kUnion_Op:
-            case SkRegion::kReplace_Op:
-            case SkRegion::kReverseDifference_Op:
-            case SkRegion::kXOR_Op: {
-                    // These ops can grow the current clip up to the extents of
-                    // the input clip, which is inverse filled, so we just set
-                    // the current clip to the device bounds.
-                    SkRect deviceBounds;
-                    SkIRect deviceIBounds;
-                    this->getDevice()->getGlobalBounds(&deviceIBounds);
-                    deviceBounds = SkRect::Make(deviceIBounds);
-
-                    // set the clip in device space
-                    SkMatrix savedMatrix = this->getTotalMatrix();
-                    this->SkCanvas::setMatrix(SkMatrix::I());
-                    this->SkCanvas::onClipRect(deviceBounds, SkRegion::kReplace_Op,
-                                               kHard_ClipEdgeStyle);
-                    this->setMatrix(savedMatrix);
-                    break;
-            }
-            default:
-                SkASSERT(0); // unhandled op?
-        }
-    } else {
-        // Not inverse filled
-        switch (op) {
-            case SkRegion::kIntersect_Op:
-            case SkRegion::kUnion_Op:
-            case SkRegion::kReplace_Op:
-                this->SkCanvas::onClipRect(bounds, op, kHard_ClipEdgeStyle);
-                break;
-            case SkRegion::kDifference_Op:
-                // Difference can only shrink the current clip.
-                // Leaving clip unchanged conservatively fullfills the contract.
-                break;
-            case SkRegion::kReverseDifference_Op:
-                // To reverse, we swap in the bounds with a replace op.
-                // As with difference, leave it unchanged.
-                this->SkCanvas::onClipRect(bounds, SkRegion::kReplace_Op, kHard_ClipEdgeStyle);
-                break;
-            case SkRegion::kXOR_Op:
-                // Be conservative, based on (A XOR B) always included in (A union B),
-                // which is always included in (bounds(A) union bounds(B))
-                this->SkCanvas::onClipRect(bounds, SkRegion::kUnion_Op, kHard_ClipEdgeStyle);
-                break;
-            default:
-                SkASSERT(0); // unhandled op?
-        }
-    }
+    rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
 }
 
 void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
@@ -1553,7 +1532,7 @@ void SkCanvas::validateClip() const {
 
     SkIRect ir;
     ir.set(0, 0, device->width(), device->height());
-    SkRasterClip tmpClip(ir);
+    SkRasterClip tmpClip(ir, fConservativeRasterClip);
 
     SkClipStack::B2TIter                iter(fClipStack);
     const SkClipStack::Element* element;
@@ -1569,7 +1548,7 @@ void SkCanvas::validateClip() const {
             default: {
                 SkPath path;
                 element->asPath(&path);
-                clip_path_helper(this, &tmpClip, path, element->getOp(), element->isAA());
+                rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA());
                 break;
             }
         }
@@ -1597,7 +1576,6 @@ bool SkCanvas::isClipRect() const {
 }
 
 bool SkCanvas::quickReject(const SkRect& rect) const {
-
     if (!rect.isFinite())
         return true;
 
@@ -1645,7 +1623,7 @@ bool SkCanvas::getClipBounds(SkRect* bounds) const {
         return false;
     }
 
-    if (NULL != bounds) {
+    if (bounds) {
         SkRect r;
         // adjust it outwards in case we are antialiasing
         const int inset = 1;
@@ -1666,7 +1644,7 @@ bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
         return false;
     }
 
-    if (NULL != bounds) {
+    if (bounds) {
         *bounds = clip.getBounds();
     }
     return true;
@@ -1676,32 +1654,10 @@ const SkMatrix& SkCanvas::getTotalMatrix() const {
     return fMCRec->fMatrix;
 }
 
-#ifdef SK_SUPPORT_LEGACY_GETCLIPTYPE
-SkCanvas::ClipType SkCanvas::getClipType() const {
-    if (fMCRec->fRasterClip.isEmpty()) {
-        return kEmpty_ClipType;
-    }
-    if (fMCRec->fRasterClip.isRect()) {
-        return kRect_ClipType;
-    }
-    return kComplex_ClipType;
-}
-#endif
-
 const SkRegion& SkCanvas::internal_private_getTotalClip() const {
     return fMCRec->fRasterClip.forceGetBW();
 }
 
-void SkCanvas::internal_private_getTotalClipAsPath(SkPath* path) const {
-    path->reset();
-
-    const SkRegion& rgn = fMCRec->fRasterClip.forceGetBW();
-    if (rgn.isEmpty()) {
-        return;
-    }
-    (void)rgn.getBoundaryPath(path);
-}
-
 GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
     SkBaseDevice* dev = this->getTopDevice();
     return dev ? dev->accessRenderTarget() : NULL;
@@ -1715,9 +1671,9 @@ SkBaseDevice* SkCanvas::createLayerDevice(const SkImageInfo& info) {
 GrContext* SkCanvas::getGrContext() {
 #if SK_SUPPORT_GPU
     SkBaseDevice* device = this->getTopDevice();
-    if (NULL != device) {
+    if (device) {
         GrRenderTarget* renderTarget = device->accessRenderTarget();
-        if (NULL != renderTarget) {
+        if (renderTarget) {
             return renderTarget->getContext();
         }
     }
@@ -1760,7 +1716,7 @@ void SkCanvas::clear(SkColor color) {
 }
 
 void SkCanvas::onDiscard() {
-    if (NULL != fSurfaceBase) {
+    if (fSurfaceBase) {
         fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
     }
 }
@@ -1930,6 +1886,17 @@ void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
     LOOPER_END
 }
 
+void SkCanvas::drawImage(const SkImage* image, SkScalar left, SkScalar top,
+                       const SkPaint* paint) {
+    image->draw(this, left, top, paint);
+}
+
+void SkCanvas::drawImageRect(const SkImage* image, const SkRect* src,
+                           const SkRect& dst,
+                           const SkPaint* paint) {
+    image->draw(this, src, dst, paint);
+}
+
 void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
                           const SkPaint* paint) {
     SkDEBUGCODE(bitmap.validate();)
@@ -2084,7 +2051,6 @@ public:
         if (device->filterTextFlags(paint, &flags)) {
             SkPaint* newPaint = fLazy.set(paint);
             newPaint->setFlags(flags.fFlags);
-            newPaint->setHinting(flags.fHinting);
             fPaint = newPaint;
         } else {
             fPaint = &paint;
@@ -2222,6 +2188,29 @@ void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPat
     LOOPER_END
 }
 
+void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
+                              const SkPaint& paint) {
+
+    // FIXME: temporarily disable quickreject for empty bounds,
+    // pending implicit blob bounds implementation.
+    if (!blob->bounds().isEmpty() && paint.canComputeFastBounds()) {
+        SkRect storage;
+
+        if (this->quickReject(paint.computeFastBounds(blob->bounds().makeOffset(x, y), &storage))) {
+            return;
+        }
+    }
+
+    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
+
+    while (iter.next()) {
+        SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
+        iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint());
+    }
+
+    LOOPER_END
+}
+
 // These will become non-virtual, so they always call the (virtual) onDraw... method
 void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
                         const SkPaint& paint) {
@@ -2239,6 +2228,12 @@ void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath&
                               const SkMatrix* matrix, const SkPaint& paint) {
     this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
 }
+void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
+                            const SkPaint& paint) {
+    if (blob) {
+        this->onDrawTextBlob(blob, x, y, paint);
+    }
+}
 
 void SkCanvas::drawVertices(VertexMode vmode, int vertexCount,
                             const SkPoint verts[], const SkPoint texs[],
@@ -2403,19 +2398,19 @@ void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
 ///////////////////////////////////////////////////////////////////////////////
 void SkCanvas::EXPERIMENTAL_optimize(const SkPicture* picture) {
     SkBaseDevice* device = this->getDevice();
-    if (NULL != device) {
+    if (device) {
         device->EXPERIMENTAL_optimize(picture);
     }
 }
 
 void SkCanvas::drawPicture(const SkPicture* picture) {
-    if (NULL != picture) {
+    if (picture) {
         this->onDrawPicture(picture, NULL, NULL);
     }
 }
 
 void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
-    if (NULL != picture) {
+    if (picture) {
         if (matrix && matrix->isIdentity()) {
             matrix = NULL;
         }
@@ -2426,7 +2421,7 @@ void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, con
 void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
                              const SkPaint* paint) {
     SkBaseDevice* device = this->getTopDevice();
-    if (NULL != device) {
+    if (device) {
         // Canvas has to first give the device the opportunity to render
         // the picture itself.
         if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
@@ -2434,9 +2429,9 @@ void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
         }
     }
 
-    SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->width(), picture->height());
+    SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
 
-    picture->draw(this);
+    picture->playback(this);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -2512,7 +2507,7 @@ SkCanvas* SkCanvas::NewRaster(const SkImageInfo& info) {
     }
 
     SkBitmap bitmap;
-    if (!bitmap.allocPixels(info)) {
+    if (!bitmap.tryAllocPixels(info)) {
         return NULL;
     }
 
@@ -2538,21 +2533,21 @@ SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_
 ///////////////////////////////////////////////////////////////////////////////
 
 SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
-                                                 const SkPaint* paint, int width, int height)
+                                                 const SkPaint* paint, const SkRect& bounds)
     : fCanvas(canvas)
     , fSaveCount(canvas->getSaveCount())
 {
-    if (NULL != paint) {
-        SkRect bounds = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
+    if (paint) {
+        SkRect newBounds = bounds;
         if (matrix) {
-            matrix->mapRect(&bounds);
+            matrix->mapRect(&newBounds);
         }
-        canvas->saveLayer(&bounds, paint);
-    } else if (NULL != matrix) {
+        canvas->saveLayer(&newBounds, paint);
+    } else if (matrix) {
         canvas->save();
     }
 
-    if (NULL != matrix) {
+    if (matrix) {
         canvas->concat(*matrix);
     }
 }