Chromium Code Reviews| Index: src/core/SkRecordDraw.cpp |
| diff --git a/src/core/SkRecordDraw.cpp b/src/core/SkRecordDraw.cpp |
| index c9e029b8db67f11a59c9844a3128f5042931dedf..8f4e84864b3b92cb90b276d91e44be340116160b 100644 |
| --- a/src/core/SkRecordDraw.cpp |
| +++ b/src/core/SkRecordDraw.cpp |
| @@ -16,10 +16,16 @@ void SkRecordDraw(const SkRecord& record, |
| if (NULL != bbh) { |
| // Draw only ops that affect pixels in the canvas's current clip. |
| - SkIRect devBounds; |
| - canvas->getClipDeviceBounds(&devBounds); |
| + SkIRect query; |
| +#if 1 // TODO: Why is this the right way to make the query? I'd think it'd be the else branch. |
|
Stephen White
2014/08/14 17:40:04
I'm not super-familiar with the BBH code, but it l
mtklein
2014/08/14 17:54:03
Yeah, stole this from there.
As far as I can tell
|
| + SkRect clipBounds; |
| + canvas->getClipBounds(&clipBounds); |
| + clipBounds.roundOut(&query); |
| +#else |
| + canvas->getClipDeviceBounds(&query); |
| +#endif |
| SkTDArray<void*> ops; |
| - bbh->search(devBounds, &ops); |
| + bbh->search(query, &ops); |
| // FIXME: QuadTree doesn't send these back in the order we inserted them. :( |
| // Also remove the sort in SkPictureData::getActiveOps()? |
| @@ -117,7 +123,9 @@ public: |
| FillBounds(const SkRecord& record, SkBBoxHierarchy* bbh) : fBounds(record.count()) { |
| // Calculate bounds for all ops. This won't go quite in order, so we'll need |
| // to store the bounds separately then feed them in to the BBH later in order. |
| + const SkIRect largest = SkIRect::MakeLargest(); |
| fCTM.setIdentity(); |
| + fClipBounds = largest; |
| for (fCurrentOp = 0; fCurrentOp < record.count(); fCurrentOp++) { |
| record.visit<void>(fCurrentOp, *this); |
| } |
| @@ -130,7 +138,7 @@ public: |
| // Any control ops not part of any Save/Restore block draw everywhere. |
| while (!fControlIndices.isEmpty()) { |
| - this->popControl(SkIRect::MakeLargest()); |
| + this->popControl(largest); |
| } |
| // Finally feed all stored bounds into the BBH. They'll be returned in this order. |
| @@ -143,28 +151,42 @@ public: |
| bbh->flushDeferredInserts(); |
| } |
| - template <typename T> void operator()(const T& r) { |
| - this->updateCTM(r); |
| - this->trackBounds(r); |
| + template <typename T> void operator()(const T& op) { |
| + this->updateCTM(op); |
| + this->updateClipBounds(op); |
| + this->trackBounds(op); |
| } |
| private: |
| struct SaveBounds { |
| - int controlOps; // Number of control ops in this Save block, including the Save. |
| - SkIRect bounds; // Bounds of everything in the block. |
| + int controlOps; // Number of control ops in this Save block, including the Save. |
| + SkIRect bounds; // Bounds of everything in the block. |
| + const SkPaint* paint; // Unowned. If set, adjusts the bounds of all ops in this block. |
| }; |
| template <typename T> void updateCTM(const T&) { /* most ops don't change the CTM */ } |
| - void updateCTM(const Restore& r) { fCTM = r.matrix; } |
| - void updateCTM(const SetMatrix& r) { fCTM = r.matrix; } |
| - void updateCTM(const Concat& r) { fCTM.preConcat(r.matrix); } |
| + void updateCTM(const Restore& op) { fCTM = op.matrix; } |
| + void updateCTM(const SetMatrix& op) { fCTM = op.matrix; } |
| + void updateCTM(const Concat& op) { fCTM.preConcat(op.matrix); } |
| + |
| + template <typename T> void updateClipBounds(const T&) { /* most ops don't change the clip */ } |
| + void updateClipBounds(const Restore& op) { fClipBounds = op.devBounds; } |
| + void updateClipBounds(const ClipPath& op) { fClipBounds = op.devBounds; } |
| + void updateClipBounds(const ClipRRect& op) { fClipBounds = op.devBounds; } |
| + void updateClipBounds(const ClipRect& op) { fClipBounds = op.devBounds; } |
| + void updateClipBounds(const ClipRegion& op) { fClipBounds = op.devBounds; } |
| + void updateClipBounds(const SaveLayer& op) { |
| + if (op.bounds) { |
| + fClipBounds.intersect(this->adjustAndMap(*op.bounds, op.paint)); |
| + } |
| + } |
| // The bounds of these ops must be calculated when we hit the Restore |
| // from the bounds of the ops in the same Save block. |
| - void trackBounds(const Save&) { this->pushSaveBlock(); } |
| + void trackBounds(const Save&) { this->pushSaveBlock(NULL); } |
| // TODO: bounds of SaveLayer may be more complicated? |
| - void trackBounds(const SaveLayer&) { this->pushSaveBlock(); } |
| - void trackBounds(const Restore&) { fBounds[fCurrentOp] = this->popSaveBlock(); } |
| + void trackBounds(const SaveLayer& op) { this->pushSaveBlock(op.paint); } |
| + void trackBounds(const Restore&) { fBounds[fCurrentOp] = this->popSaveBlock(); } |
| void trackBounds(const Concat&) { this->pushControl(); } |
| void trackBounds(const SetMatrix&) { this->pushControl(); } |
| @@ -179,12 +201,9 @@ private: |
| this->updateSaveBounds(fBounds[fCurrentOp]); |
| } |
| - // TODO: remove this trivially-safe default when done bounding all ops |
| - template <typename T> SkIRect bounds(const T&) { return SkIRect::MakeLargest(); } |
| - |
| - void pushSaveBlock() { |
| + void pushSaveBlock(const SkPaint* paint) { |
| // Starting a new Save block. Push a new entry to represent that. |
| - SaveBounds sb = { 0, SkIRect::MakeEmpty() }; |
| + SaveBounds sb = { 0, SkIRect::MakeEmpty(), paint }; |
| fSaveStack.push(sb); |
| this->pushControl(); |
| } |
| @@ -223,10 +242,36 @@ private: |
| } |
| } |
| - SkIRect bounds(const NoOp&) { return SkIRect::MakeEmpty(); } // NoOps don't draw anywhere. |
| + // TODO: Remove this default when done bounding all ops. |
| + template <typename T> SkIRect bounds(const T&) { return fClipBounds; } |
| + SkIRect bounds(const Clear&) { return SkIRect::MakeLargest(); } // Ignores the clip |
| + SkIRect bounds(const NoOp&) { return SkIRect::MakeEmpty(); } // NoOps don't draw anywhere. |
| + |
| + // Adjust rect for all paints that may affect its geometry, then map it to device space. |
| + SkIRect adjustAndMap(SkRect rect, const SkPaint* paint) { |
| + // Adjust rect for its own paint. |
| + if (paint && paint->canComputeFastBounds()) { |
| + rect = paint->computeFastBounds(rect, &rect); |
|
Stephen White
2014/08/14 17:23:07
If you have a paint that can't computeFastBounds()
mtklein
2014/08/14 17:54:03
Thanks, good catch. All the bounds are the clip r
|
| + } |
| + // Adjust rect for all the paints from the SaveLayers we're inside. |
| + // For SaveLayers, only image filters will affect the bounds. |
| + for (int i = fSaveStack.count() - 1; i >= 0; i--) { |
| + if (fSaveStack[i].paint && |
| + fSaveStack[i].paint->getImageFilter() && |
| + fSaveStack[i].paint->canComputeFastBounds()) { |
| + rect = fSaveStack[i].paint->computeFastBounds(rect, &rect); |
| + } |
| + } |
| + // Map the rect back to device space. |
| + fCTM.mapRect(&rect); |
| + SkIRect devRect; |
| + rect.roundOut(&devRect); |
| + return devRect; |
| + } |
| SkAutoTMalloc<SkIRect> fBounds; // One for each op in the record. |
| SkMatrix fCTM; |
| + SkIRect fClipBounds; |
| unsigned fCurrentOp; |
| SkTDArray<SaveBounds> fSaveStack; |
| SkTDArray<unsigned> fControlIndices; |