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 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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. |
| 98 // |
| 99 // The interesting part here is how to calculate bounds for ops which don't |
| 100 // have intrinsic bounds. What is the bounds of a Save or a Translate? |
| 101 // |
| 102 // We answer this by thinking about a particular definition of bounds: if I |
| 103 // don't execute this op, pixels in this rectangle might draw incorrectly. So |
| 104 // the bounds of a Save, a Translate, a Restore, etc. are the union of the |
| 105 // bounds of Draw* ops that they might have an effect on. For any given |
| 106 // Save/Restore block, the bounds of the Save, the Restore, and any other |
| 107 // non-drawing ("control") ops inside are exactly the union of the bounds of |
| 108 // the drawing ops inside that block. |
| 109 // |
| 110 // To implement this, we keep a stack of active Save blocks. As we consume ops |
| 111 // inside the Save/Restore block, drawing ops are unioned with the bounds of |
| 112 // the block, and control ops are stashed away for later. When we finish the |
| 113 // block with a Restore, our bounds are complete, and we go back and fill them |
| 114 // in for all the control ops we stashed away. |
103 class FillBounds : SkNoncopyable { | 115 class FillBounds : SkNoncopyable { |
104 public: | 116 public: |
105 explicit FillBounds(SkBBoxHierarchy* bbh) : fBBH(bbh), fIndex(0) {} | 117 FillBounds(const SkRecord& record, SkBBoxHierarchy* bbh) : fBounds(record.co
unt()) { |
106 ~FillBounds() { fBBH->flushDeferredInserts(); } | 118 // Calculate bounds for all ops. This won't go quite in order, so we'll
need |
| 119 // to store the bounds separately then feed them in to the BBH later in
order. |
| 120 for (fCurrentOp = 0; fCurrentOp < record.count(); fCurrentOp++) { |
| 121 record.visit<void>(fCurrentOp, *this); |
| 122 } |
107 | 123 |
108 uintptr_t index() const { return fIndex; } | 124 // If we have any lingering unpaired Saves, simulate restores to make |
109 void next() { ++fIndex; } | 125 // sure all ops in those Save blocks have their bounds calculated. |
| 126 while (!fSaveStack.isEmpty()) { |
| 127 this->popSaveBlock(); |
| 128 } |
| 129 |
| 130 // Any control ops not part of any Save/Restore block draw everywhere. |
| 131 while (!fControlIndices.isEmpty()) { |
| 132 this->popControl(SkIRect::MakeLargest()); |
| 133 } |
| 134 |
| 135 // Finally feed all stored bounds into the BBH. They'll be returned in
this order. |
| 136 SkASSERT(NULL != bbh); |
| 137 for (uintptr_t i = 0; i < record.count(); i++) { |
| 138 if (!fBounds[i].isEmpty()) { |
| 139 bbh->insert((void*)i, fBounds[i], true/*ok to defer*/); |
| 140 } |
| 141 } |
| 142 bbh->flushDeferredInserts(); |
| 143 } |
110 | 144 |
111 template <typename T> void operator()(const T& r) { | 145 template <typename T> void operator()(const T& r) { |
112 // MakeLargest() is a trivially safe default for ops that haven't been b
ounded yet. | 146 this->trackBounds(r); |
113 this->insert(this->index(), SkIRect::MakeLargest()); | |
114 } | 147 } |
115 | 148 |
116 private: | 149 private: |
117 void insert(uintptr_t opIndex, const SkIRect& bounds) { | 150 struct SaveBounds { |
118 fBBH->insert((void*)opIndex, bounds, true/*ok to defer*/); | 151 int controlOps; // Number of control ops in this Save block, including
the Save. |
| 152 SkIRect bounds; // Bounds of everything in the block. |
| 153 }; |
| 154 |
| 155 // The bounds of these ops must be calculated when we hit the Restore |
| 156 // from the bounds of the ops in the same Save block. |
| 157 void trackBounds(const Save&) { this->pushSaveBlock(); } |
| 158 // TODO: bounds of SaveLayer may be more complicated? |
| 159 void trackBounds(const SaveLayer&) { this->pushSaveBlock(); } |
| 160 void trackBounds(const Restore&) { fBounds[fCurrentOp] = this->popSaveBlo
ck(); } |
| 161 |
| 162 void trackBounds(const Concat&) { this->pushControl(); } |
| 163 void trackBounds(const SetMatrix&) { this->pushControl(); } |
| 164 void trackBounds(const ClipRect&) { this->pushControl(); } |
| 165 void trackBounds(const ClipRRect&) { this->pushControl(); } |
| 166 void trackBounds(const ClipPath&) { this->pushControl(); } |
| 167 void trackBounds(const ClipRegion&) { this->pushControl(); } |
| 168 |
| 169 // For all other ops, we can calculate and store the bounds directly now. |
| 170 template <typename T> void trackBounds(const T& op) { |
| 171 fBounds[fCurrentOp] = this->bounds(op); |
| 172 this->updateSaveBounds(fBounds[fCurrentOp]); |
119 } | 173 } |
120 | 174 |
121 SkBBoxHierarchy* fBBH; // Unowned. The BBH is guaranteed to be ref'd for ou
r lifetime. | 175 // TODO: remove this trivially-safe default when done bounding all ops |
122 uintptr_t fIndex; | 176 template <typename T> SkIRect bounds(const T&) { return SkIRect::MakeLargest
(); } |
| 177 |
| 178 void pushSaveBlock() { |
| 179 // Starting a new Save block. Push a new entry to represent that. |
| 180 SaveBounds sb = { 0, SkIRect::MakeEmpty() }; |
| 181 fSaveStack.push(sb); |
| 182 this->pushControl(); |
| 183 } |
| 184 |
| 185 SkIRect popSaveBlock() { |
| 186 // We're done the Save block. Apply the block's bounds to all control o
ps inside it. |
| 187 SaveBounds sb; |
| 188 fSaveStack.pop(&sb); |
| 189 while (sb.controlOps --> 0) { |
| 190 this->popControl(sb.bounds); |
| 191 } |
| 192 |
| 193 // This whole Save block may be part another Save block. |
| 194 this->updateSaveBounds(sb.bounds); |
| 195 |
| 196 // If called from a real Restore (not a phony one for balance), it'll ne
ed the bounds. |
| 197 return sb.bounds; |
| 198 } |
| 199 |
| 200 void pushControl() { |
| 201 fControlIndices.push(fCurrentOp); |
| 202 if (!fSaveStack.isEmpty()) { |
| 203 fSaveStack.top().controlOps++; |
| 204 } |
| 205 } |
| 206 |
| 207 void popControl(const SkIRect& bounds) { |
| 208 fBounds[fControlIndices.top()] = bounds; |
| 209 fControlIndices.pop(); |
| 210 } |
| 211 |
| 212 void updateSaveBounds(const SkIRect& bounds) { |
| 213 // If we're in a Save block, expand its bounds to cover these bounds too
. |
| 214 if (!fSaveStack.isEmpty()) { |
| 215 fSaveStack.top().bounds.join(bounds); |
| 216 } |
| 217 } |
| 218 |
| 219 SkIRect bounds(const NoOp&) { return SkIRect::MakeEmpty(); } // NoOps don't
draw anywhere. |
| 220 |
| 221 SkAutoTMalloc<SkIRect> fBounds; // One for each op in the record. |
| 222 unsigned fCurrentOp; |
| 223 SkTDArray<SaveBounds> fSaveStack; |
| 224 SkTDArray<unsigned> fControlIndices; |
123 }; | 225 }; |
124 | 226 |
125 } // namespace SkRecords | 227 } // namespace SkRecords |
126 | 228 |
127 void SkRecordFillBounds(const SkRecord& record, SkBBoxHierarchy* bbh) { | 229 void SkRecordFillBounds(const SkRecord& record, SkBBoxHierarchy* bbh) { |
128 SkASSERT(NULL != bbh); | 230 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 } | 231 } |
OLD | NEW |