Chromium Code Reviews| Index: src/core/SkRecordDraw.cpp |
| diff --git a/src/core/SkRecordDraw.cpp b/src/core/SkRecordDraw.cpp |
| index 8be9e005f6c3846b363c23851eb4a9d93cce4e37..fa32b05f869c7edf177f6e10899fcb5cc61d2477 100644 |
| --- a/src/core/SkRecordDraw.cpp |
| +++ b/src/core/SkRecordDraw.cpp |
| @@ -15,17 +15,12 @@ void SkRecordDraw(const SkRecord& record, |
| SkAutoCanvasRestore saveRestore(canvas, true /*save now, restore at exit*/); |
| if (NULL != bbh) { |
| - SkASSERT(bbh->getCount() == SkToInt(record.count())); |
| - |
| // Draw only ops that affect pixels in the canvas's current clip. |
| SkIRect devBounds; |
| canvas->getClipDeviceBounds(&devBounds); |
| SkTDArray<void*> ops; |
| bbh->search(devBounds, &ops); |
| - // Until we start filling in real bounds, we should get every op back. |
| - SkASSERT(ops.count() == SkToInt(record.count())); |
| - |
| // FIXME: QuadTree doesn't send these back in the order we inserted them. :( |
| // Also remove the sort in SkPictureData::getActiveOps()? |
| if (ops.count() > 0) { |
| @@ -102,31 +97,118 @@ DRAW(DrawVertices, drawVertices(r.vmode, r.vertexCount, r.vertices, r.texs, r.co |
| // This is an SkRecord visitor that fills an SkBBoxHierarchy. |
|
robertphillips
2014/08/13 18:53:46
// Every operation (including save* and control op
|
| class FillBounds : SkNoncopyable { |
| public: |
| - explicit FillBounds(SkBBoxHierarchy* bbh) : fBBH(bbh), fIndex(0) {} |
| - ~FillBounds() { fBBH->flushDeferredInserts(); } |
| + 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. |
| + for (fI = 0; fI < record.count(); fI++) { |
| + record.visit<void>(fI, *this); |
| + } |
| + |
| + // If we have any lingering unpaired Saves, simulate restores to make |
| + // sure all ops in those Save blocks have their bounds calculated. |
| + while (!fSaves.isEmpty()) { |
| + this->popSaveBlock(); |
| + } |
| + |
| + // Any control ops not part of any Save/Restore block draw everywhere. |
| + while (!fControls.isEmpty()) { |
| + this->popControl(SkIRect::MakeLargest()); |
| + } |
| - uintptr_t index() const { return fIndex; } |
| - void next() { ++fIndex; } |
| + // Finally feed all stored bounds into the BBH. They'll be returned in this order. |
| + SkASSERT(NULL != bbh); |
| + for (uintptr_t i = 0; i < record.count(); i++) { |
| + if (!fBounds[i].isEmpty()) { |
| + bbh->insert((void*)i, fBounds[i], true/*ok to defer*/); |
| + } |
| + } |
| + bbh->flushDeferredInserts(); |
| + } |
| template <typename T> void operator()(const T& r) { |
| - // MakeLargest() is a trivially safe default for ops that haven't been bounded yet. |
| - this->insert(this->index(), SkIRect::MakeLargest()); |
| + this->trackBounds(r); |
| } |
| private: |
| - void insert(uintptr_t opIndex, const SkIRect& bounds) { |
| - fBBH->insert((void*)opIndex, bounds, true/*ok to defer*/); |
| + struct SaveBounds { |
| + int controlOps; // Number of control ops in this Save block, including the Save. |
| + SkIRect bounds; // Bounds of everything in the block. |
| + }; |
| + |
| + // 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(); } |
| + // TODO: bounds of SaveLayer may be more complicated? |
| + void trackBounds(const SaveLayer&) { this->pushSaveBlock(); } |
| + void trackBounds(const Restore&) { fBounds[fI] = this->popSaveBlock(); } |
| + |
| + void trackBounds(const Concat&) { this->pushControl(); } |
| + void trackBounds(const SetMatrix&) { this->pushControl(); } |
| + void trackBounds(const ClipRect&) { this->pushControl(); } |
| + void trackBounds(const ClipRRect&) { this->pushControl(); } |
| + void trackBounds(const ClipPath&) { this->pushControl(); } |
| + void trackBounds(const ClipRegion&) { this->pushControl(); } |
| + |
| + // For all other ops, we can calculate and store the bounds directly now. |
| + template <typename T> void trackBounds(const T& op) { |
| + fBounds[fI] = this->bounds(op); // Store our own bounds. |
| + this->updateSaveBounds(fBounds[fI]); // If we're in a Save, expand its bounds to contain us. |
| + } |
| + |
| + // TODO: remove this trivially-safe default when done bounding all ops |
| + template <typename T> SkIRect bounds(const T&) { return SkIRect::MakeLargest(); } |
| + |
| + void pushSaveBlock() { |
| + // Starting a new Save block. Push a new entry to represent that. |
| + SaveBounds sb = { 0, SkIRect::MakeEmpty() }; |
| + fSaves.push(sb); |
| + this->pushControl(); |
| + } |
| + |
| + SkIRect popSaveBlock() { |
|
robertphillips
2014/08/13 18:53:46
We're done _with_ ... ?
|
| + // We're done the Save block. Apply the block's bounds to all control ops inside it. |
| + SaveBounds sb; |
| + fSaves.pop(&sb); |
| + while (sb.controlOps --> 0) { |
| + this->popControl(sb.bounds); |
| + } |
| + |
| + // This whole Save block may be part another Save block. |
| + this->updateSaveBounds(sb.bounds); |
| + |
| + // If called from a real Restore (not a phony one for balance), it'll need the bounds. |
| + return sb.bounds; |
| + } |
| + |
| + void pushControl() { |
| + fControls.push(fI); |
| + if (!fSaves.isEmpty()) { |
| + fSaves.top().controlOps++; |
| + } |
| } |
| - SkBBoxHierarchy* fBBH; // Unowned. The BBH is guaranteed to be ref'd for our lifetime. |
| - uintptr_t fIndex; |
| + void popControl(const SkIRect& bounds) { |
| + fBounds[fControls.top()] = bounds; |
| + fControls.pop(); |
| + } |
| + |
| + void updateSaveBounds(const SkIRect& bounds) { |
| + // If we're in a Save block, expand its bounds to cover these bounds too. |
| + if (!fSaves.isEmpty()) { |
| + fSaves.top().bounds.join(bounds); |
| + } |
| + } |
| + |
| + SkIRect bounds(const NoOp&) { return SkIRect::MakeEmpty(); } // NoOps don't draw anywhere. |
| + |
| + SkAutoTMalloc<SkIRect> fBounds; // One for each op in the record. |
|
robertphillips
2014/08/13 18:53:46
fI -> fCurOp, fCurBound, fCurOpIndex ?
|
| + unsigned fI; |
|
robertphillips
2014/08/13 18:53:46
// Contains both saves and saveLayers ?
fSaves ->
|
| + SkTDArray<SaveBounds> fSaves; |
|
robertphillips
2014/08/13 18:53:46
// A unified list of control operations encountere
|
| + SkTDArray<unsigned> fControls; |
| }; |
| } // namespace SkRecords |
| void SkRecordFillBounds(const SkRecord& record, SkBBoxHierarchy* bbh) { |
| - SkASSERT(NULL != bbh); |
| - for(SkRecords::FillBounds fb(bbh); fb.index() < record.count(); fb.next()) { |
| - record.visit<void>(fb.index(), fb); |
| - } |
| + SkRecords::FillBounds(record, bbh); |
| } |