| Index: src/core/SkCanvas.cpp
|
| diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
|
| index 99786151abb150dd9500c46121079f1af43a5b81..62d60da178bd790582acdf5aba3c7db92791e0bb 100644
|
| --- a/src/core/SkCanvas.cpp
|
| +++ b/src/core/SkCanvas.cpp
|
| @@ -81,9 +81,12 @@
|
| 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) {
|
| - if (device) {
|
| + 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);
|
| }
|
| @@ -151,11 +154,10 @@
|
| */
|
| class SkCanvas::MCRec {
|
| public:
|
| + SkRasterClip fRasterClip;
|
| SkMatrix fMatrix;
|
| - SkRasterClip fRasterClip;
|
| 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
|
| @@ -164,22 +166,21 @@
|
| */
|
| DeviceCM* fTopLayer;
|
|
|
| - MCRec(const MCRec* prev) {
|
| - if (prev) {
|
| - fMatrix = prev->fMatrix;
|
| - fRasterClip = prev->fRasterClip;
|
| -
|
| - fFilter = prev->fFilter;
|
| - SkSafeRef(fFilter);
|
| -
|
| - fTopLayer = prev->fTopLayer;
|
| - } else { // no prev
|
| - fMatrix.reset();
|
| - fFilter = NULL;
|
| - fTopLayer = NULL;
|
| - }
|
| + MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
|
| + fMatrix.reset();
|
| + fFilter = NULL;
|
| + fLayer = 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();
|
| }
|
| @@ -381,7 +382,8 @@
|
|
|
| ////////////////////////////////////////////////////////////////////////////
|
|
|
| -SkBaseDevice* SkCanvas::init(SkBaseDevice* device) {
|
| +SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
|
| + fConservativeRasterClip = SkToBool(flags & kConservativeRasterClip_InitFlag);
|
| fCachedLocalClipBounds.setEmpty();
|
| fCachedLocalClipBoundsDirty = true;
|
| fAllowSoftClip = true;
|
| @@ -391,10 +393,14 @@
|
| fCullCount = 0;
|
| fMetaData = NULL;
|
|
|
| + if (device && device->forceConservativeRasterClip()) {
|
| + fConservativeRasterClip = true;
|
| + }
|
| +
|
| fMCRec = (MCRec*)fMCStack.push_back();
|
| - new (fMCRec) MCRec(NULL);
|
| -
|
| - fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL, NULL));
|
| + new (fMCRec) MCRec(fConservativeRasterClip);
|
| +
|
| + fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL, NULL, fConservativeRasterClip));
|
| fMCRec->fTopLayer = fMCRec->fLayer;
|
|
|
| fSurfaceBase = NULL;
|
| @@ -412,25 +418,54 @@
|
| {
|
| 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))
|
| {
|
| 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))
|
| +{
|
| + inc_canvas();
|
| +
|
| + this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice, (width, height)), flags)->unref();
|
| +}
|
| +
|
| +SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
|
| + : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
|
| +{
|
| + inc_canvas();
|
| +
|
| + this->init(device, flags);
|
| }
|
|
|
| SkCanvas::SkCanvas(SkBaseDevice* device)
|
| : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
|
| {
|
| inc_canvas();
|
| -
|
| - this->init(device);
|
| +
|
| + this->init(device, kDefault_InitFlags);
|
| }
|
|
|
| SkCanvas::SkCanvas(const SkBitmap& bitmap)
|
| @@ -438,7 +473,7 @@
|
| {
|
| inc_canvas();
|
|
|
| - this->init(SkNEW_ARGS(SkBitmapDevice, (bitmap)))->unref();
|
| + this->init(SkNEW_ARGS(SkBitmapDevice, (bitmap)), kDefault_InitFlags)->unref();
|
| }
|
|
|
| SkCanvas::~SkCanvas() {
|
| @@ -734,7 +769,7 @@
|
| 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();
|
| @@ -866,7 +901,8 @@
|
| }
|
|
|
| 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;
|
| @@ -1286,7 +1322,7 @@
|
|
|
| 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
|
| @@ -1421,82 +1457,6 @@
|
| rasterclip_path(&fMCRec->fRasterClip, this, 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?
|
| - }
|
| - }
|
| -}
|
| -
|
| void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
|
| this->onClipRegion(rgn, op);
|
| }
|
| @@ -1525,7 +1485,7 @@
|
|
|
| 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 +1529,6 @@
|
| }
|
|
|
| bool SkCanvas::quickReject(const SkRect& rect) const {
|
| -
|
| if (!rect.isFinite())
|
| return true;
|
|
|
|
|