Chromium Code Reviews| Index: src/core/SkCanvas.cpp |
| diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp |
| index 083a8ed7e8a8cea5ccb505b1d6a3537a8ed95fd7..69e078517539eb31c85293b1e2821c8ebe2b01ab 100644 |
| --- a/src/core/SkCanvas.cpp |
| +++ b/src/core/SkCanvas.cpp |
| @@ -170,8 +170,6 @@ private: |
| */ |
| class SkCanvas::MCRec { |
| public: |
| - SkRasterClip fRasterClip; |
| - SkMatrix fMatrix; |
| SkDrawFilter* fFilter; // the current filter (or null) |
| DeviceCM* fLayer; |
| /* If there are any layers in the stack, this points to the top-most |
| @@ -180,22 +178,26 @@ public: |
| reference counted, since the real owner is either our fLayer field, |
| or a previous one in a lower level.) |
| */ |
| - DeviceCM* fTopLayer; |
| + DeviceCM* fTopLayer; |
| + SkRasterClip fRasterClip; |
| + SkMatrix fMatrix; |
| + int fDeferredSaveCount; |
|
f(malita)
2014/12/10 19:49:33
I always imagined this to be an unsigned, but yeah
|
| MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) { |
| - fMatrix.reset(); |
| fFilter = NULL; |
| fLayer = NULL; |
| fTopLayer = NULL; |
| + fMatrix.reset(); |
| + fDeferredSaveCount = 0; |
| // don't bother initializing fNext |
| inc_rec(); |
| } |
| - MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip) { |
| - fMatrix = prev.fMatrix; |
| + MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) { |
| fFilter = SkSafeRef(prev.fFilter); |
| fLayer = NULL; |
| fTopLayer = prev.fTopLayer; |
| + fDeferredSaveCount = 0; |
| // don't bother initializing fNext |
| inc_rec(); |
| @@ -423,6 +425,8 @@ SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) { |
| fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL, NULL, fConservativeRasterClip)); |
| fMCRec->fTopLayer = fMCRec->fLayer; |
| + fCallingWillSave = false; |
| + |
| fSurfaceBase = NULL; |
| if (device) { |
| @@ -785,21 +789,51 @@ void SkCanvas::updateDeviceCMCache() { |
| /////////////////////////////////////////////////////////////////////////////// |
| +void SkCanvas::checkForDeferredSave() { |
| + if (fMCRec->fDeferredSaveCount > 0) { |
| + fMCRec->fDeferredSaveCount -= 1; |
| + this->doSave(); |
| + } |
| +} |
| + |
| int SkCanvas::getSaveCount() const { |
|
f(malita)
2014/12/10 19:49:33
To avoid perf surprises, we should probably track
reed1
2014/12/10 20:06:36
Probably true :(
|
| - return fMCStack.count(); |
| + int count = 0; |
| + SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart); |
| + for (;;) { |
| + const MCRec* rec = (const MCRec*)iter.next(); |
|
f(malita)
2014/12/10 19:49:33
I think this will miss all deferred saves on the i
reed1
2014/12/10 20:06:36
next() returns the first one : its a funny pattern
|
| + if (!rec) { |
| + break; |
| + } |
| + count += 1 + rec->fDeferredSaveCount; |
| + } |
| + return count; |
|
f(malita)
2014/12/10 19:49:33
Would it be simpler to just iterate over all MCRec
reed1
2014/12/10 20:06:35
see above
f(malita)
2014/12/10 20:13:58
Hmm, then something's not clicking: do we need to
|
| } |
| int SkCanvas::save() { |
| + fMCRec->fDeferredSaveCount += 1; |
| +#if 0 |
| + this->checkForDeferredSave(); |
| +#endif |
| + return this->getSaveCount() - 1; // return our prev value |
| +} |
| + |
| +void SkCanvas::doSave() { |
| + fCallingWillSave = true; |
| this->willSave(); |
| - return this->internalSave(); |
| + fCallingWillSave = false; |
|
robertphillips
2014/12/10 18:43:53
Do we need this cast ?
reed1
2014/12/10 20:06:35
Done.
|
| + (void)this->internalSave(); |
| } |
| void SkCanvas::restore() { |
| - // check for underflow |
| - if (fMCStack.count() > 1) { |
| - this->willRestore(); |
| - this->internalRestore(); |
| - this->didRestore(); |
| + if (fMCRec->fDeferredSaveCount > 0) { |
| + fMCRec->fDeferredSaveCount -= 1; |
| + } else { |
| + // check for underflow |
| + if (fMCStack.count() > 1) { |
| + this->willRestore(); |
| + this->internalRestore(); |
| + this->didRestore(); |
| + } |
| } |
| } |
| @@ -815,16 +849,12 @@ void SkCanvas::restoreToCount(int count) { |
| } |
| } |
| -int SkCanvas::internalSave() { |
| - int saveCount = this->getSaveCount(); // record this before the actual save |
| - |
| +void SkCanvas::internalSave() { |
| MCRec* newTop = (MCRec*)fMCStack.push_back(); |
| new (newTop) MCRec(*fMCRec); // balanced in restore() |
| fMCRec = newTop; |
| fClipStack.save(); |
| - |
| - return saveCount; |
| } |
| static bool bounds_affects_clip(SkCanvas::SaveFlags flags) { |
| @@ -881,16 +911,17 @@ bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags, |
| int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) { |
| SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag); |
| - return this->internalSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag, false, strategy); |
| + this->internalSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag, false, strategy); |
| + return this->getSaveCount() - 1; |
| } |
| -int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, |
| - SaveFlags flags) { |
| +int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) { |
| SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags); |
| - return this->internalSaveLayer(bounds, paint, flags, false, strategy); |
| + this->internalSaveLayer(bounds, paint, flags, false, strategy); |
| + return this->getSaveCount() - 1; |
| } |
| -int SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags, |
| +void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags, |
| bool justForImageFilter, SaveLayerStrategy strategy) { |
| #ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG |
| flags |= kClipToLayer_SaveFlag; |
| @@ -898,19 +929,19 @@ int SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, Save |
| // do this before we create the layer. We don't call the public save() since |
| // that would invoke a possibly overridden virtual |
| - int count = this->internalSave(); |
| + this->internalSave(); |
| fDeviceCMDirty = true; |
| SkIRect ir; |
| if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : NULL)) { |
| - return count; |
| + return; |
| } |
| // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about |
| // the clipRectBounds() call above? |
| if (kNoLayer_SaveLayerStrategy == strategy) { |
| - return count; |
| + return; |
| } |
| // Kill the imagefilter if our device doesn't allow it |
| @@ -919,7 +950,7 @@ int SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, Save |
| if (!this->getTopDevice()->allowImageFilter(paint->getImageFilter())) { |
| if (justForImageFilter) { |
| // early exit if the layer was just for the imageFilter |
| - return count; |
| + return; |
| } |
| SkPaint* p = lazyP.set(*paint); |
| p->setImageFilter(NULL); |
| @@ -934,7 +965,7 @@ int SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, Save |
| SkBaseDevice* device = this->getTopDevice(); |
| if (NULL == device) { |
| SkDebugf("Unable to find device for layer."); |
| - return count; |
| + return; |
| } |
| SkBaseDevice::Usage usage = SkBaseDevice::kSaveLayer_Usage; |
| @@ -945,7 +976,7 @@ int SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, Save |
| fProps.pixelGeometry())); |
| if (NULL == device) { |
| SkDebugf("Unable to create device for layer."); |
| - return count; |
| + return; |
| } |
| device->setOrigin(ir.fLeft, ir.fTop); |
| @@ -958,7 +989,6 @@ int SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, Save |
| fMCRec->fTopLayer = layer; // this field is NOT an owner of layer |
| fSaveLayerCount += 1; |
| - return count; |
| } |
| int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) { |
| @@ -1286,6 +1316,7 @@ void SkCanvas::concat(const SkMatrix& matrix) { |
| return; |
| } |
| + this->checkForDeferredSave(); |
| fDeviceCMDirty = true; |
| fCachedLocalClipBoundsDirty = true; |
| fMCRec->fMatrix.preConcat(matrix); |
| @@ -1294,6 +1325,7 @@ void SkCanvas::concat(const SkMatrix& matrix) { |
| } |
| void SkCanvas::setMatrix(const SkMatrix& matrix) { |
| + this->checkForDeferredSave(); |
| fDeviceCMDirty = true; |
| fCachedLocalClipBoundsDirty = true; |
| fMCRec->fMatrix = matrix; |
| @@ -1310,6 +1342,7 @@ void SkCanvas::resetMatrix() { |
| ////////////////////////////////////////////////////////////////////////////// |
| void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { |
| + this->checkForDeferredSave(); |
| ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; |
| this->onClipRect(rect, op, edgeStyle); |
| } |
| @@ -1367,6 +1400,7 @@ static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPa |
| } |
| void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { |
| + this->checkForDeferredSave(); |
| ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; |
| if (rrect.isRect()) { |
| this->onClipRect(rrect.getBounds(), op, edgeStyle); |
| @@ -1402,6 +1436,7 @@ void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle |
| } |
| void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { |
| + this->checkForDeferredSave(); |
| ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; |
| SkRect r; |
| if (!path.isInverseFillType() && path.isRect(&r)) { |
| @@ -1484,6 +1519,7 @@ void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edg |
| } |
| void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { |
| + this->checkForDeferredSave(); |
| this->onClipRegion(rgn, op); |
| } |