Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(130)

Unified Diff: src/core/SkRecordDraw.cpp

Issue 474983002: SkRecordDraw: incorporate clip into BBH (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: sign comparison Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | src/core/SkRecorder.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/core/SkRecordDraw.cpp
diff --git a/src/core/SkRecordDraw.cpp b/src/core/SkRecordDraw.cpp
index c9e029b8db67f11a59c9844a3128f5042931dedf..46241d72aca40cffe9239472b9c0b5cc72829057 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.
+ 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();
+ fCurrentClipBounds = 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,44 @@ 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 */ }
+ // Each of these devBounds fields is the state of the device bounds after the op.
+ // So Restore's devBounds are those bounds saved by its paired Save or SaveLayer.
+ void updateClipBounds(const Restore& op) { fCurrentClipBounds = op.devBounds; }
+ void updateClipBounds(const ClipPath& op) { fCurrentClipBounds = op.devBounds; }
+ void updateClipBounds(const ClipRRect& op) { fCurrentClipBounds = op.devBounds; }
+ void updateClipBounds(const ClipRect& op) { fCurrentClipBounds = op.devBounds; }
+ void updateClipBounds(const ClipRegion& op) { fCurrentClipBounds = op.devBounds; }
+ void updateClipBounds(const SaveLayer& op) {
+ if (op.bounds) {
+ fCurrentClipBounds.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 +203,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,11 +244,54 @@ 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 fCurrentClipBounds; }
+ 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) {
+ if (paint->canComputeFastBounds()) {
+ rect = paint->computeFastBounds(rect, &rect);
+ } else {
+ // The paint could do anything. The only safe answer is the current clip.
+ return fCurrentClipBounds;
+ }
+ }
- SkAutoTMalloc<SkIRect> fBounds; // One for each op in the record.
- SkMatrix fCTM;
+ // 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()) {
+ if (paint->canComputeFastBounds()) {
+ rect = fSaveStack[i].paint->computeFastBounds(rect, &rect);
+ } else {
+ // Same deal as above.
+ return fCurrentClipBounds;
+ }
+ }
+ }
+
+ // Map the rect back to device space.
+ fCTM.mapRect(&rect);
+ SkIRect devRect;
+ rect.roundOut(&devRect);
+ return devRect;
+ }
+
+ // Conservative device bounds for each op in the SkRecord.
+ SkAutoTMalloc<SkIRect> fBounds;
+
+ // We walk fCurrentOp through the SkRecord, as we go using updateCTM()
+ // and updateClipBounds() to maintain the exact CTM (fCTM) and conservative
+ // device bounds of the current clip (fCurrentClipBounds).
unsigned fCurrentOp;
+ SkMatrix fCTM;
+ SkIRect fCurrentClipBounds;
+
+ // Used to track the bounds of Save/Restore blocks and the control ops inside them.
SkTDArray<SaveBounds> fSaveStack;
SkTDArray<unsigned> fControlIndices;
};
« no previous file with comments | « no previous file | src/core/SkRecorder.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698