Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkRecordDraw.h" | 8 #include "SkRecordDraw.h" |
| 9 #include "SkTSort.h" | 9 #include "SkTSort.h" |
| 10 | 10 |
| 11 void SkRecordDraw(const SkRecord& record, | 11 void SkRecordDraw(const SkRecord& record, |
| 12 SkCanvas* canvas, | 12 SkCanvas* canvas, |
| 13 const SkBBoxHierarchy* bbh, | 13 const SkBBoxHierarchy* bbh, |
| 14 SkDrawPictureCallback* callback) { | 14 SkDrawPictureCallback* callback) { |
| 15 SkAutoCanvasRestore saveRestore(canvas, true /*save now, restore at exit*/); | 15 SkAutoCanvasRestore saveRestore(canvas, true /*save now, restore at exit*/); |
| 16 | 16 |
| 17 if (NULL != bbh) { | 17 if (NULL != bbh) { |
| 18 SkASSERT(bbh->getCount() == SkToInt(record.count())); | |
| 19 | |
| 20 // Draw only ops that affect pixels in the canvas's current clip. | 18 // Draw only ops that affect pixels in the canvas's current clip. |
| 21 SkIRect devBounds; | 19 SkIRect devBounds; |
| 22 canvas->getClipDeviceBounds(&devBounds); | 20 canvas->getClipDeviceBounds(&devBounds); |
| 23 SkTDArray<void*> ops; | 21 SkTDArray<void*> ops; |
| 24 bbh->search(devBounds, &ops); | 22 bbh->search(devBounds, &ops); |
| 25 | 23 |
| 26 // Until we start filling in real bounds, we should get every op back. | |
| 27 SkASSERT(ops.count() == SkToInt(record.count())); | |
| 28 | |
| 29 // FIXME: QuadTree doesn't send these back in the order we inserted them . :( | 24 // FIXME: QuadTree doesn't send these back in the order we inserted them . :( |
| 30 // Also remove the sort in SkPictureData::getActiveOps()? | 25 // Also remove the sort in SkPictureData::getActiveOps()? |
| 31 if (ops.count() > 0) { | 26 if (ops.count() > 0) { |
| 32 SkTQSort(ops.begin(), ops.end() - 1, SkTCompareLT<void*>()); | 27 SkTQSort(ops.begin(), ops.end() - 1, SkTCompareLT<void*>()); |
| 33 } | 28 } |
| 34 | 29 |
| 35 SkRecords::Draw draw(canvas); | 30 SkRecords::Draw draw(canvas); |
| 36 for (int i = 0; i < ops.count(); i++) { | 31 for (int i = 0; i < ops.count(); i++) { |
| 37 if (NULL != callback && callback->abortDrawing()) { | 32 if (NULL != callback && callback->abortDrawing()) { |
| 38 return; | 33 return; |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 92 DRAW(DrawRRect, drawRRect(r.rrect, r.paint)); | 87 DRAW(DrawRRect, drawRRect(r.rrect, r.paint)); |
| 93 DRAW(DrawRect, drawRect(r.rect, r.paint)); | 88 DRAW(DrawRect, drawRect(r.rect, r.paint)); |
| 94 DRAW(DrawSprite, drawSprite(shallow_copy(r.bitmap), r.left, r.top, r.paint)); | 89 DRAW(DrawSprite, drawSprite(shallow_copy(r.bitmap), r.left, r.top, r.paint)); |
| 95 DRAW(DrawText, drawText(r.text, r.byteLength, r.x, r.y, r.paint)); | 90 DRAW(DrawText, drawText(r.text, r.byteLength, r.x, r.y, r.paint)); |
| 96 DRAW(DrawTextOnPath, drawTextOnPath(r.text, r.byteLength, r.path, r.matrix, r.pa int)); | 91 DRAW(DrawTextOnPath, drawTextOnPath(r.text, r.byteLength, r.path, r.matrix, r.pa int)); |
| 97 DRAW(DrawVertices, drawVertices(r.vmode, r.vertexCount, r.vertices, r.texs, r.co lors, | 92 DRAW(DrawVertices, drawVertices(r.vmode, r.vertexCount, r.vertices, r.texs, r.co lors, |
| 98 r.xmode.get(), r.indices, r.indexCount, r.paint) ); | 93 r.xmode.get(), r.indices, r.indexCount, r.paint) ); |
| 99 #undef DRAW | 94 #undef DRAW |
| 100 | 95 |
| 101 | 96 |
| 102 // This is an SkRecord visitor that fills an SkBBoxHierarchy. | 97 // This is an SkRecord visitor that fills an SkBBoxHierarchy. |
|
robertphillips
2014/08/13 18:53:46
// Every operation (including save* and control op
| |
| 103 class FillBounds : SkNoncopyable { | 98 class FillBounds : SkNoncopyable { |
| 104 public: | 99 public: |
| 105 explicit FillBounds(SkBBoxHierarchy* bbh) : fBBH(bbh), fIndex(0) {} | 100 FillBounds(const SkRecord& record, SkBBoxHierarchy* bbh) : fBounds(record.co unt()) { |
| 106 ~FillBounds() { fBBH->flushDeferredInserts(); } | 101 // Calculate bounds for all ops. This won't go quite in order, so we'll need |
| 102 // to store the bounds separately then feed them in to the BBH later in order. | |
| 103 for (fI = 0; fI < record.count(); fI++) { | |
| 104 record.visit<void>(fI, *this); | |
| 105 } | |
| 107 | 106 |
| 108 uintptr_t index() const { return fIndex; } | 107 // If we have any lingering unpaired Saves, simulate restores to make |
| 109 void next() { ++fIndex; } | 108 // sure all ops in those Save blocks have their bounds calculated. |
| 109 while (!fSaves.isEmpty()) { | |
| 110 this->popSaveBlock(); | |
| 111 } | |
| 112 | |
| 113 // Any control ops not part of any Save/Restore block draw everywhere. | |
| 114 while (!fControls.isEmpty()) { | |
| 115 this->popControl(SkIRect::MakeLargest()); | |
| 116 } | |
| 117 | |
| 118 // Finally feed all stored bounds into the BBH. They'll be returned in this order. | |
| 119 SkASSERT(NULL != bbh); | |
| 120 for (uintptr_t i = 0; i < record.count(); i++) { | |
| 121 if (!fBounds[i].isEmpty()) { | |
| 122 bbh->insert((void*)i, fBounds[i], true/*ok to defer*/); | |
| 123 } | |
| 124 } | |
| 125 bbh->flushDeferredInserts(); | |
| 126 } | |
| 110 | 127 |
| 111 template <typename T> void operator()(const T& r) { | 128 template <typename T> void operator()(const T& r) { |
| 112 // MakeLargest() is a trivially safe default for ops that haven't been b ounded yet. | 129 this->trackBounds(r); |
| 113 this->insert(this->index(), SkIRect::MakeLargest()); | |
| 114 } | 130 } |
| 115 | 131 |
| 116 private: | 132 private: |
| 117 void insert(uintptr_t opIndex, const SkIRect& bounds) { | 133 struct SaveBounds { |
| 118 fBBH->insert((void*)opIndex, bounds, true/*ok to defer*/); | 134 int controlOps; // Number of control ops in this Save block, including the Save. |
| 135 SkIRect bounds; // Bounds of everything in the block. | |
| 136 }; | |
| 137 | |
| 138 // The bounds of these ops must be calculated when we hit the Restore | |
| 139 // from the bounds of the ops in the same Save block. | |
| 140 void trackBounds(const Save&) { this->pushSaveBlock(); } | |
| 141 // TODO: bounds of SaveLayer may be more complicated? | |
| 142 void trackBounds(const SaveLayer&) { this->pushSaveBlock(); } | |
| 143 void trackBounds(const Restore&) { fBounds[fI] = this->popSaveBlock(); } | |
| 144 | |
| 145 void trackBounds(const Concat&) { this->pushControl(); } | |
| 146 void trackBounds(const SetMatrix&) { this->pushControl(); } | |
| 147 void trackBounds(const ClipRect&) { this->pushControl(); } | |
| 148 void trackBounds(const ClipRRect&) { this->pushControl(); } | |
| 149 void trackBounds(const ClipPath&) { this->pushControl(); } | |
| 150 void trackBounds(const ClipRegion&) { this->pushControl(); } | |
| 151 | |
| 152 // For all other ops, we can calculate and store the bounds directly now. | |
| 153 template <typename T> void trackBounds(const T& op) { | |
| 154 fBounds[fI] = this->bounds(op); // Store our own bounds. | |
| 155 this->updateSaveBounds(fBounds[fI]); // If we're in a Save, expand its b ounds to contain us. | |
| 119 } | 156 } |
| 120 | 157 |
| 121 SkBBoxHierarchy* fBBH; // Unowned. The BBH is guaranteed to be ref'd for ou r lifetime. | 158 // TODO: remove this trivially-safe default when done bounding all ops |
| 122 uintptr_t fIndex; | 159 template <typename T> SkIRect bounds(const T&) { return SkIRect::MakeLargest (); } |
| 160 | |
| 161 void pushSaveBlock() { | |
| 162 // Starting a new Save block. Push a new entry to represent that. | |
| 163 SaveBounds sb = { 0, SkIRect::MakeEmpty() }; | |
| 164 fSaves.push(sb); | |
| 165 this->pushControl(); | |
| 166 } | |
| 167 | |
| 168 SkIRect popSaveBlock() { | |
|
robertphillips
2014/08/13 18:53:46
We're done _with_ ... ?
| |
| 169 // We're done the Save block. Apply the block's bounds to all control o ps inside it. | |
| 170 SaveBounds sb; | |
| 171 fSaves.pop(&sb); | |
| 172 while (sb.controlOps --> 0) { | |
| 173 this->popControl(sb.bounds); | |
| 174 } | |
| 175 | |
| 176 // This whole Save block may be part another Save block. | |
| 177 this->updateSaveBounds(sb.bounds); | |
| 178 | |
| 179 // If called from a real Restore (not a phony one for balance), it'll ne ed the bounds. | |
| 180 return sb.bounds; | |
| 181 } | |
| 182 | |
| 183 void pushControl() { | |
| 184 fControls.push(fI); | |
| 185 if (!fSaves.isEmpty()) { | |
| 186 fSaves.top().controlOps++; | |
| 187 } | |
| 188 } | |
| 189 | |
| 190 void popControl(const SkIRect& bounds) { | |
| 191 fBounds[fControls.top()] = bounds; | |
| 192 fControls.pop(); | |
| 193 } | |
| 194 | |
| 195 void updateSaveBounds(const SkIRect& bounds) { | |
| 196 // If we're in a Save block, expand its bounds to cover these bounds too . | |
| 197 if (!fSaves.isEmpty()) { | |
| 198 fSaves.top().bounds.join(bounds); | |
| 199 } | |
| 200 } | |
| 201 | |
| 202 SkIRect bounds(const NoOp&) { return SkIRect::MakeEmpty(); } // NoOps don't draw anywhere. | |
| 203 | |
| 204 SkAutoTMalloc<SkIRect> fBounds; // One for each op in the record. | |
|
robertphillips
2014/08/13 18:53:46
fI -> fCurOp, fCurBound, fCurOpIndex ?
| |
| 205 unsigned fI; | |
|
robertphillips
2014/08/13 18:53:46
// Contains both saves and saveLayers ?
fSaves ->
| |
| 206 SkTDArray<SaveBounds> fSaves; | |
|
robertphillips
2014/08/13 18:53:46
// A unified list of control operations encountere
| |
| 207 SkTDArray<unsigned> fControls; | |
| 123 }; | 208 }; |
| 124 | 209 |
| 125 } // namespace SkRecords | 210 } // namespace SkRecords |
| 126 | 211 |
| 127 void SkRecordFillBounds(const SkRecord& record, SkBBoxHierarchy* bbh) { | 212 void SkRecordFillBounds(const SkRecord& record, SkBBoxHierarchy* bbh) { |
| 128 SkASSERT(NULL != bbh); | 213 SkRecords::FillBounds(record, bbh); |
| 129 for(SkRecords::FillBounds fb(bbh); fb.index() < record.count(); fb.next()) { | |
| 130 record.visit<void>(fb.index(), fb); | |
| 131 } | |
| 132 } | 214 } |
| OLD | NEW |