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 "SkPatchUtils.h" | 9 #include "SkPatchUtils.h" |
10 | 10 |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
106 DRAW(DrawSprite, drawSprite(shallow_copy(r.bitmap), r.left, r.top, r.paint)); | 106 DRAW(DrawSprite, drawSprite(shallow_copy(r.bitmap), r.left, r.top, r.paint)); |
107 DRAW(DrawText, drawText(r.text, r.byteLength, r.x, r.y, r.paint)); | 107 DRAW(DrawText, drawText(r.text, r.byteLength, r.x, r.y, r.paint)); |
108 DRAW(DrawTextBlob, drawTextBlob(r.blob, r.x, r.y, r.paint)); | 108 DRAW(DrawTextBlob, drawTextBlob(r.blob, r.x, r.y, r.paint)); |
109 DRAW(DrawTextOnPath, drawTextOnPath(r.text, r.byteLength, r.path, r.matrix, r.pa
int)); | 109 DRAW(DrawTextOnPath, drawTextOnPath(r.text, r.byteLength, r.path, r.matrix, r.pa
int)); |
110 DRAW(DrawVertices, drawVertices(r.vmode, r.vertexCount, r.vertices, r.texs, r.co
lors, | 110 DRAW(DrawVertices, drawVertices(r.vmode, r.vertexCount, r.vertices, r.texs, r.co
lors, |
111 r.xmode.get(), r.indices, r.indexCount, r.paint)
); | 111 r.xmode.get(), r.indices, r.indexCount, r.paint)
); |
112 DRAW(DrawData, drawData(r.data, r.length)); | 112 DRAW(DrawData, drawData(r.data, r.length)); |
113 #undef DRAW | 113 #undef DRAW |
114 | 114 |
115 | 115 |
| 116 // This looks silly, I know. Why not just use SkRect::MakeLargest()? |
| 117 // In practice, this is well large enough, and it has a few extra advantages: |
| 118 // it fits in an SkIRect, and we can munge it a little in both SkRect and |
| 119 // SKIRect space without worrying about overflow. |
| 120 static const SkRect kUnbounded = { -2e9f, -2e9f, 2e9f, 2e9f }; |
| 121 |
| 122 |
116 // This is an SkRecord visitor that fills an SkBBoxHierarchy. | 123 // This is an SkRecord visitor that fills an SkBBoxHierarchy. |
117 // | 124 // |
118 // The interesting part here is how to calculate bounds for ops which don't | 125 // The interesting part here is how to calculate bounds for ops which don't |
119 // have intrinsic bounds. What is the bounds of a Save or a Translate? | 126 // have intrinsic bounds. What is the bounds of a Save or a Translate? |
120 // | 127 // |
121 // We answer this by thinking about a particular definition of bounds: if I | 128 // We answer this by thinking about a particular definition of bounds: if I |
122 // don't execute this op, pixels in this rectangle might draw incorrectly. So | 129 // don't execute this op, pixels in this rectangle might draw incorrectly. So |
123 // the bounds of a Save, a Translate, a Restore, etc. are the union of the | 130 // the bounds of a Save, a Translate, a Restore, etc. are the union of the |
124 // bounds of Draw* ops that they might have an effect on. For any given | 131 // bounds of Draw* ops that they might have an effect on. For any given |
125 // Save/Restore block, the bounds of the Save, the Restore, and any other | 132 // Save/Restore block, the bounds of the Save, the Restore, and any other |
126 // non-drawing ("control") ops inside are exactly the union of the bounds of | 133 // non-drawing ("control") ops inside are exactly the union of the bounds of |
127 // the drawing ops inside that block. | 134 // the drawing ops inside that block. |
128 // | 135 // |
129 // To implement this, we keep a stack of active Save blocks. As we consume ops | 136 // To implement this, we keep a stack of active Save blocks. As we consume ops |
130 // inside the Save/Restore block, drawing ops are unioned with the bounds of | 137 // inside the Save/Restore block, drawing ops are unioned with the bounds of |
131 // the block, and control ops are stashed away for later. When we finish the | 138 // the block, and control ops are stashed away for later. When we finish the |
132 // block with a Restore, our bounds are complete, and we go back and fill them | 139 // block with a Restore, our bounds are complete, and we go back and fill them |
133 // in for all the control ops we stashed away. | 140 // in for all the control ops we stashed away. |
134 class FillBounds : SkNoncopyable { | 141 class FillBounds : SkNoncopyable { |
135 public: | 142 public: |
136 FillBounds(const SkRecord& record, SkBBoxHierarchy* bbh) : fBounds(record.co
unt()) { | 143 FillBounds(const SkRecord& record, SkBBoxHierarchy* bbh) : fBounds(record.co
unt()) { |
137 // Calculate bounds for all ops. This won't go quite in order, so we'll
need | 144 // Calculate bounds for all ops. This won't go quite in order, so we'll
need |
138 // to store the bounds separately then feed them in to the BBH later in
order. | 145 // to store the bounds separately then feed them in to the BBH later in
order. |
139 const Bounds largest = Bounds::MakeLargest(); | |
140 fCTM = &SkMatrix::I(); | 146 fCTM = &SkMatrix::I(); |
141 fCurrentClipBounds = largest; | 147 fCurrentClipBounds = kUnbounded; |
142 for (fCurrentOp = 0; fCurrentOp < record.count(); fCurrentOp++) { | 148 for (fCurrentOp = 0; fCurrentOp < record.count(); fCurrentOp++) { |
143 record.visit<void>(fCurrentOp, *this); | 149 record.visit<void>(fCurrentOp, *this); |
144 } | 150 } |
145 | 151 |
146 // If we have any lingering unpaired Saves, simulate restores to make | 152 // If we have any lingering unpaired Saves, simulate restores to make |
147 // sure all ops in those Save blocks have their bounds calculated. | 153 // sure all ops in those Save blocks have their bounds calculated. |
148 while (!fSaveStack.isEmpty()) { | 154 while (!fSaveStack.isEmpty()) { |
149 this->popSaveBlock(); | 155 this->popSaveBlock(); |
150 } | 156 } |
151 | 157 |
152 // Any control ops not part of any Save/Restore block draw everywhere. | 158 // Any control ops not part of any Save/Restore block draw everywhere. |
153 while (!fControlIndices.isEmpty()) { | 159 while (!fControlIndices.isEmpty()) { |
154 this->popControl(largest); | 160 this->popControl(kUnbounded); |
155 } | 161 } |
156 | 162 |
157 // Finally feed all stored bounds into the BBH. They'll be returned in
this order. | 163 // Finally feed all stored bounds into the BBH. They'll be returned in
this order. |
158 SkASSERT(bbh); | 164 SkASSERT(bbh); |
159 for (unsigned i = 0; i < record.count(); i++) { | 165 for (unsigned i = 0; i < record.count(); i++) { |
160 if (!fBounds[i].isEmpty()) { | 166 if (!fBounds[i].isEmpty()) { |
161 bbh->insert(i, fBounds[i], true/*ok to defer*/); | 167 bbh->insert(i, fBounds[i], true/*ok to defer*/); |
162 } | 168 } |
163 } | 169 } |
164 bbh->flushDeferredInserts(); | 170 bbh->flushDeferredInserts(); |
(...skipping 27 matching lines...) Expand all Loading... |
192 void updateClipBounds(const ClipPath& op) { this->updateClipBoundsForClipO
p(op.devBounds); } | 198 void updateClipBounds(const ClipPath& op) { this->updateClipBoundsForClipO
p(op.devBounds); } |
193 void updateClipBounds(const ClipRRect& op) { this->updateClipBoundsForClipO
p(op.devBounds); } | 199 void updateClipBounds(const ClipRRect& op) { this->updateClipBoundsForClipO
p(op.devBounds); } |
194 void updateClipBounds(const ClipRect& op) { this->updateClipBoundsForClipO
p(op.devBounds); } | 200 void updateClipBounds(const ClipRect& op) { this->updateClipBoundsForClipO
p(op.devBounds); } |
195 void updateClipBounds(const ClipRegion& op) { this->updateClipBoundsForClipO
p(op.devBounds); } | 201 void updateClipBounds(const ClipRegion& op) { this->updateClipBoundsForClipO
p(op.devBounds); } |
196 | 202 |
197 // The bounds of clip ops need to be adjusted for the paints of saveLayers t
hey're inside. | 203 // The bounds of clip ops need to be adjusted for the paints of saveLayers t
hey're inside. |
198 void updateClipBoundsForClipOp(const SkIRect& devBounds) { | 204 void updateClipBoundsForClipOp(const SkIRect& devBounds) { |
199 Bounds clip = SkRect::Make(devBounds); | 205 Bounds clip = SkRect::Make(devBounds); |
200 // We don't call adjustAndMap() because as its last step it would inters
ect the adjusted | 206 // We don't call adjustAndMap() because as its last step it would inters
ect the adjusted |
201 // clip bounds with the previous clip, exactly what we can't do when the
clip grows. | 207 // clip bounds with the previous clip, exactly what we can't do when the
clip grows. |
202 fCurrentClipBounds = this->adjustForSaveLayerPaints(&clip) ? clip : Boun
ds::MakeLargest(); | 208 fCurrentClipBounds = this->adjustForSaveLayerPaints(&clip) ? clip : kUnb
ounded; |
203 } | 209 } |
204 | 210 |
205 // Restore holds the devBounds for the clip after the {save,saveLayer}/resto
re block completes. | 211 // Restore holds the devBounds for the clip after the {save,saveLayer}/resto
re block completes. |
206 void updateClipBounds(const Restore& op) { | 212 void updateClipBounds(const Restore& op) { |
207 // This is just like the clip ops above, but we need to skip the effects
(if any) of our | 213 // This is just like the clip ops above, but we need to skip the effects
(if any) of our |
208 // paired saveLayer (if it is one); it has not yet been popped off the s
ave stack. Our | 214 // paired saveLayer (if it is one); it has not yet been popped off the s
ave stack. Our |
209 // devBounds reflect the state of the world after the saveLayer/restore
block is done, | 215 // devBounds reflect the state of the world after the saveLayer/restore
block is done, |
210 // so they are not affected by the saveLayer's paint. | 216 // so they are not affected by the saveLayer's paint. |
211 const int kSavesToIgnore = 1; | 217 const int kSavesToIgnore = 1; |
212 Bounds clip = SkRect::Make(op.devBounds); | 218 Bounds clip = SkRect::Make(op.devBounds); |
213 fCurrentClipBounds = | 219 fCurrentClipBounds = |
214 this->adjustForSaveLayerPaints(&clip, kSavesToIgnore) ? clip : Bound
s::MakeLargest(); | 220 this->adjustForSaveLayerPaints(&clip, kSavesToIgnore) ? clip : kUnbo
unded; |
215 } | 221 } |
216 | 222 |
217 // We also take advantage of SaveLayer bounds when present to further cut th
e clip down. | 223 // We also take advantage of SaveLayer bounds when present to further cut th
e clip down. |
218 void updateClipBounds(const SaveLayer& op) { | 224 void updateClipBounds(const SaveLayer& op) { |
219 if (op.bounds) { | 225 if (op.bounds) { |
220 // adjustAndMap() intersects these layer bounds with the previous cl
ip for us. | 226 // adjustAndMap() intersects these layer bounds with the previous cl
ip for us. |
221 fCurrentClipBounds = this->adjustAndMap(*op.bounds, op.paint); | 227 fCurrentClipBounds = this->adjustAndMap(*op.bounds, op.paint); |
222 } | 228 } |
223 } | 229 } |
224 | 230 |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
328 void updateSaveBounds(const Bounds& bounds) { | 334 void updateSaveBounds(const Bounds& bounds) { |
329 // If we're in a Save block, expand its bounds to cover these bounds too
. | 335 // If we're in a Save block, expand its bounds to cover these bounds too
. |
330 if (!fSaveStack.isEmpty()) { | 336 if (!fSaveStack.isEmpty()) { |
331 fSaveStack.top().bounds.join(bounds); | 337 fSaveStack.top().bounds.join(bounds); |
332 } | 338 } |
333 } | 339 } |
334 | 340 |
335 // FIXME: this method could use better bounds | 341 // FIXME: this method could use better bounds |
336 Bounds bounds(const DrawText&) const { return fCurrentClipBounds; } | 342 Bounds bounds(const DrawText&) const { return fCurrentClipBounds; } |
337 | 343 |
338 Bounds bounds(const Clear&) const { return Bounds::MakeLargest(); } // Igno
res the clip. | 344 Bounds bounds(const Clear&) const { return kUnbounded; } // Igno
res the clip. |
339 Bounds bounds(const DrawPaint&) const { return fCurrentClipBounds; } | 345 Bounds bounds(const DrawPaint&) const { return fCurrentClipBounds; } |
340 Bounds bounds(const NoOp&) const { return Bounds::MakeEmpty(); } // NoOp
s don't draw. | 346 Bounds bounds(const NoOp&) const { return Bounds::MakeEmpty(); } // NoOp
s don't draw. |
341 | 347 |
342 Bounds bounds(const DrawSprite& op) const { | 348 Bounds bounds(const DrawSprite& op) const { |
343 const SkBitmap& bm = op.bitmap; | 349 const SkBitmap& bm = op.bitmap; |
344 return Bounds::MakeXYWH(op.left, op.top, bm.width(), bm.height()); // I
gnores the matrix. | 350 return Bounds::MakeXYWH(op.left, op.top, bm.width(), bm.height()); // I
gnores the matrix. |
345 } | 351 } |
346 | 352 |
347 Bounds bounds(const DrawRect& op) const { return this->adjustAndMap(op.rect,
&op.paint); } | 353 Bounds bounds(const DrawRect& op) const { return this->adjustAndMap(op.rect,
&op.paint); } |
348 Bounds bounds(const DrawOval& op) const { return this->adjustAndMap(op.oval,
&op.paint); } | 354 Bounds bounds(const DrawOval& op) const { return this->adjustAndMap(op.oval,
&op.paint); } |
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
539 // Used to track the bounds of Save/Restore blocks and the control ops insid
e them. | 545 // Used to track the bounds of Save/Restore blocks and the control ops insid
e them. |
540 SkTDArray<SaveBounds> fSaveStack; | 546 SkTDArray<SaveBounds> fSaveStack; |
541 SkTDArray<unsigned> fControlIndices; | 547 SkTDArray<unsigned> fControlIndices; |
542 }; | 548 }; |
543 | 549 |
544 } // namespace SkRecords | 550 } // namespace SkRecords |
545 | 551 |
546 void SkRecordFillBounds(const SkRecord& record, SkBBoxHierarchy* bbh) { | 552 void SkRecordFillBounds(const SkRecord& record, SkBBoxHierarchy* bbh) { |
547 SkRecords::FillBounds(record, bbh); | 553 SkRecords::FillBounds(record, bbh); |
548 } | 554 } |
OLD | NEW |