| Index: src/core/SkRecordDraw.cpp
 | 
| diff --git a/src/core/SkRecordDraw.cpp b/src/core/SkRecordDraw.cpp
 | 
| index d29e0b8c48c2f21edf706156c30bbededfb6e65e..e075074f40ec1df2238d1b70bdca5a360bfbca09 100644
 | 
| --- a/src/core/SkRecordDraw.cpp
 | 
| +++ b/src/core/SkRecordDraw.cpp
 | 
| @@ -6,14 +6,46 @@
 | 
|   */
 | 
|  
 | 
|  #include "SkRecordDraw.h"
 | 
| +#include "SkTSort.h"
 | 
|  
 | 
| -void SkRecordDraw(const SkRecord& record, SkCanvas* canvas, SkDrawPictureCallback* callback) {
 | 
| +void SkRecordDraw(const SkRecord& record,
 | 
| +                  SkCanvas* canvas,
 | 
| +                  const SkBBoxHierarchy* bbh,
 | 
| +                  SkDrawPictureCallback* callback) {
 | 
|      SkAutoCanvasRestore saveRestore(canvas, true /*save now, restore at exit*/);
 | 
| -    for (SkRecords::Draw draw(canvas); draw.index() < record.count(); draw.next()) {
 | 
| -        if (NULL != callback && callback->abortDrawing()) {
 | 
| -            return;
 | 
| +
 | 
| +    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.  :(
 | 
| +        if (ops.count() > 0) {
 | 
| +            SkTQSort(ops.begin(), ops.end() - 1, SkTCompareLT<void*>());
 | 
| +        }
 | 
| +
 | 
| +        SkRecords::Draw draw(canvas);
 | 
| +        for (int i = 0; i < ops.count(); i++) {
 | 
| +            if (NULL != callback && callback->abortDrawing()) {
 | 
| +                return;
 | 
| +            }
 | 
| +            record.visit<void>((uintptr_t)ops[i], draw);  // See FillBounds below.
 | 
| +        }
 | 
| +    } else {
 | 
| +        // Draw all ops.
 | 
| +        for (SkRecords::Draw draw(canvas); draw.index() < record.count(); draw.next()) {
 | 
| +            if (NULL != callback && callback->abortDrawing()) {
 | 
| +                return;
 | 
| +            }
 | 
| +            record.visit<void>(draw.index(), draw);
 | 
|          }
 | 
| -        record.visit<void>(draw.index(), draw);
 | 
|      }
 | 
|  }
 | 
|  
 | 
| @@ -65,4 +97,35 @@ DRAW(DrawVertices, drawVertices(r.vmode, r.vertexCount, r.vertices, r.texs, r.co
 | 
|                                  r.xmode.get(), r.indices, r.indexCount, r.paint));
 | 
|  #undef DRAW
 | 
|  
 | 
| +
 | 
| +// This is an SkRecord visitor that fills an SkBBoxHierarchy.
 | 
| +class FillBounds : SkNoncopyable {
 | 
| +public:
 | 
| +    explicit FillBounds(SkBBoxHierarchy* bbh) : fBBH(bbh), fIndex(0) {}
 | 
| +    ~FillBounds() { fBBH->flushDeferredInserts(); }
 | 
| +
 | 
| +    uintptr_t index() const { return fIndex; }
 | 
| +    void next() { ++fIndex; }
 | 
| +
 | 
| +    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());
 | 
| +    }
 | 
| +
 | 
| +private:
 | 
| +    void insert(uintptr_t opIndex, const SkIRect& bounds) {
 | 
| +        fBBH->insert((void*)opIndex, bounds, true/*ok to defer*/);
 | 
| +    }
 | 
| +
 | 
| +    SkBBoxHierarchy* fBBH;  // Unowned. The BBH is guaranteed to be ref'd for our lifetime.
 | 
| +    uintptr_t fIndex;
 | 
| +};
 | 
| +
 | 
|  }  // 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);
 | 
| +    }
 | 
| +}
 | 
| 
 |