Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(884)

Side by Side Diff: src/core/SkRecordDraw.h

Issue 698643002: Expose FillBounds to allow GrPictureUtils::CollectLayers to be layered on top of it (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Fix Windows conversion complaints Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « include/core/SkPicture.h ('k') | src/core/SkRecordDraw.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 #ifndef SkRecordDraw_DEFINED 8 #ifndef SkRecordDraw_DEFINED
9 #define SkRecordDraw_DEFINED 9 #define SkRecordDraw_DEFINED
10 10
11 #include "SkBBoxHierarchy.h" 11 #include "SkBBoxHierarchy.h"
12 #include "SkCanvas.h" 12 #include "SkCanvas.h"
13 #include "SkDrawPictureCallback.h" 13 #include "SkDrawPictureCallback.h"
14 #include "SkMatrix.h" 14 #include "SkMatrix.h"
15 #include "SkPatchUtils.h"
15 #include "SkRecord.h" 16 #include "SkRecord.h"
16 17
17 // Fill a BBH to be used by SkRecordDraw to accelerate playback. 18 // Fill a BBH to be used by SkRecordDraw to accelerate playback.
18 void SkRecordFillBounds(const SkRect& cullRect, const SkRecord&, SkBBoxHierarchy *); 19 void SkRecordFillBounds(const SkRect& cullRect, const SkRecord&, SkBBoxHierarchy *);
19 20
20 // Draw an SkRecord into an SkCanvas. A convenience wrapper around SkRecords::D raw. 21 // Draw an SkRecord into an SkCanvas. A convenience wrapper around SkRecords::D raw.
21 void SkRecordDraw(const SkRecord&, SkCanvas*, const SkBBoxHierarchy*, SkDrawPict ureCallback*); 22 void SkRecordDraw(const SkRecord&, SkCanvas*, const SkBBoxHierarchy*, SkDrawPict ureCallback*);
22 23
23 // Draw a portion of an SkRecord into an SkCanvas while replacing clears with dr awRects. 24 // Draw a portion of an SkRecord into an SkCanvas while replacing clears with dr awRects.
24 // When drawing a portion of an SkRecord the CTM on the passed in canvas must be 25 // When drawing a portion of an SkRecord the CTM on the passed in canvas must be
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
67 p.setColor(c.color); 68 p.setColor(c.color);
68 DrawRect drawRect(p, fClearRect); 69 DrawRect drawRect(p, fClearRect);
69 this->INHERITED::operator()(drawRect); 70 this->INHERITED::operator()(drawRect);
70 } 71 }
71 72
72 private: 73 private:
73 const SkRect fClearRect; 74 const SkRect fClearRect;
74 typedef Draw INHERITED; 75 typedef Draw INHERITED;
75 }; 76 };
76 77
78 // This is an SkRecord visitor that fills an SkBBoxHierarchy.
79 //
80 // The interesting part here is how to calculate bounds for ops which don't
81 // have intrinsic bounds. What is the bounds of a Save or a Translate?
82 //
83 // We answer this by thinking about a particular definition of bounds: if I
84 // don't execute this op, pixels in this rectangle might draw incorrectly. So
85 // the bounds of a Save, a Translate, a Restore, etc. are the union of the
86 // bounds of Draw* ops that they might have an effect on. For any given
87 // Save/Restore block, the bounds of the Save, the Restore, and any other
88 // non-drawing ("control") ops inside are exactly the union of the bounds of
89 // the drawing ops inside that block.
90 //
91 // To implement this, we keep a stack of active Save blocks. As we consume ops
92 // inside the Save/Restore block, drawing ops are unioned with the bounds of
93 // the block, and control ops are stashed away for later. When we finish the
94 // block with a Restore, our bounds are complete, and we go back and fill them
95 // in for all the control ops we stashed away.
96 class FillBounds : SkNoncopyable {
97 public:
98 FillBounds(const SkRect& cullRect, const SkRecord& record, SkBBoxHierarchy* bbh);
99
100 void setCurrentOp(unsigned currentOp) { fCurrentOp = currentOp; }
101 void cleanUp();
102
103 template <typename T> void operator()(const T& op) {
104 this->updateCTM(op);
105 this->updateClipBounds(op);
106 this->trackBounds(op);
107 }
108
109 // In FillBounds, SkRect are in local coordinates, Bounds are translated bac k to identity space.
110 typedef SkRect Bounds;
111
112 unsigned currentOp() const { return fCurrentOp; }
113 const SkMatrix& ctm() const { return *fCTM; }
114 const Bounds& currentClipBounds() const { return fCurrentClipBounds; }
115
116 Bounds adjustAndMap(SkRect rect, const SkPaint* paint) const;
117 const Bounds& getBounds(unsigned index) const { return fBounds[index]; }
118
119 private:
120 struct SaveBounds {
121 int controlOps; // Number of control ops in this Save block, incl uding the Save.
122 Bounds bounds; // Bounds of everything in the block.
123 const SkPaint* paint; // Unowned. If set, adjusts the bounds of all op s in this block.
124 };
125
126 static void AdjustTextForFontMetrics(SkRect* rect, const SkPaint& paint);
127
128 template <typename T> void updateCTM(const T&) {}
129 template <typename T> void updateClipBounds(const T&) {}
130 template <typename T> void trackBounds(const T& op) {
131 fBounds[fCurrentOp] = this->bounds(op);
132 this->updateSaveBounds(fBounds[fCurrentOp]);
133 }
134 template <typename T> Bounds bounds(const T&) const;
135
136 void updateClipBoundsForClipOp(const SkIRect& devBounds);
137
138 void pushSaveBlock(const SkPaint* paint);
139 Bounds popSaveBlock();
140 void pushControl();
141 void popControl(const Bounds& bounds);
142 void updateSaveBounds(const Bounds& bounds);
143
144 bool adjustForSaveLayerPaints(SkRect* rect, int savesToIgnore = 0) const;
145
146 const unsigned int fNumRecords;
147
148 // The BBH being filled in
149 SkBBoxHierarchy* fBBH;
150
151 // We do not guarantee anything for operations outside of the cull rect
152 const SkRect fCullRect;
153
154 // Conservative identity-space bounds for each op in the SkRecord.
155 SkAutoTMalloc<Bounds> fBounds;
156
157 // We walk fCurrentOp through the SkRecord, as we go using updateCTM()
158 // and updateClipBounds() to maintain the exact CTM (fCTM) and conservative
159 // identity-space bounds of the current clip (fCurrentClipBounds).
160 unsigned fCurrentOp;
161 const SkMatrix* fCTM;
162 Bounds fCurrentClipBounds;
163
164 // Used to track the bounds of Save/Restore blocks and the control ops insid e them.
165 SkTDArray<SaveBounds> fSaveStack;
166 SkTDArray<unsigned> fControlIndices;
167 };
168
169 // Only Restore and SetMatrix change the CTM.
170 template <> inline void FillBounds::updateCTM(const Restore& op) { fCTM = &op. matrix; }
171 template <> inline void FillBounds::updateCTM(const SetMatrix& op) { fCTM = &op. matrix; }
172
173 // Clip{Path,RRect,Rect,Region} obviously change the clip. They all know their bounds already.
174 template <> inline void FillBounds::updateClipBounds(const ClipPath& op) { thi s->updateClipBoundsForClipOp(op.devBounds); }
175 template <> inline void FillBounds::updateClipBounds(const ClipRRect& op) { thi s->updateClipBoundsForClipOp(op.devBounds); }
176 template <> inline void FillBounds::updateClipBounds(const ClipRect& op) { thi s->updateClipBoundsForClipOp(op.devBounds); }
177 template <> inline void FillBounds::updateClipBounds(const ClipRegion& op) { thi s->updateClipBoundsForClipOp(op.devBounds); }
178
179 // Restore holds the devBounds for the clip after the {save,saveLayer}/restore b lock completes.
180 template <> inline void FillBounds::updateClipBounds(const Restore& op) {
181 // This is just like the clip ops above, but we need to skip the effects (if any) of our
182 // paired saveLayer (if it is one); it has not yet been popped off the save stack. Our
183 // devBounds reflect the state of the world after the saveLayer/restore bloc k is done,
184 // so they are not affected by the saveLayer's paint.
185 const int kSavesToIgnore = 1;
186 Bounds clip = SkRect::Make(op.devBounds);
187 fCurrentClipBounds =
188 this->adjustForSaveLayerPaints(&clip, kSavesToIgnore) ? clip : fCullRect ;
189 }
190
191 // We also take advantage of SaveLayer bounds when present to further cut the cl ip down.
192 template <> inline void FillBounds::updateClipBounds(const SaveLayer& op) {
193 if (op.bounds) {
194 // adjustAndMap() intersects these layer bounds with the previous clip f or us.
195 fCurrentClipBounds = this->adjustAndMap(*op.bounds, op.paint);
196 }
197 }
198
199 template <> inline void FillBounds::trackBounds(const Save&) { this->pu shSaveBlock(NULL); }
200 template <> inline void FillBounds::trackBounds(const SaveLayer& op) { this->pu shSaveBlock(op.paint); }
201 template <> inline void FillBounds::trackBounds(const Restore&) { fBounds[fCurre ntOp] = this->popSaveBlock(); }
202
203 template <> inline void FillBounds::trackBounds(const SetMatrix&) { this ->pushControl(); }
204 template <> inline void FillBounds::trackBounds(const ClipRect&) { this ->pushControl(); }
205 template <> inline void FillBounds::trackBounds(const ClipRRect&) { this ->pushControl(); }
206 template <> inline void FillBounds::trackBounds(const ClipPath&) { this ->pushControl(); }
207 template <> inline void FillBounds::trackBounds(const ClipRegion&) { this ->pushControl(); }
208 template <> inline void FillBounds::trackBounds(const PushCull&) { this ->pushControl(); }
209 template <> inline void FillBounds::trackBounds(const PopCull&) { this ->pushControl(); }
210 template <> inline void FillBounds::trackBounds(const BeginCommentGroup&) { this ->pushControl(); }
211 template <> inline void FillBounds::trackBounds(const AddComment&) { this ->pushControl(); }
212 template <> inline void FillBounds::trackBounds(const EndCommentGroup&) { this ->pushControl(); }
213 template <> inline void FillBounds::trackBounds(const DrawData&) { this ->pushControl(); }
214
215 // FIXME: this method could use better bounds
216 template <> inline FillBounds::Bounds FillBounds::bounds(const DrawText&) const { return fCurrentClipBounds; }
217
218 template <> inline FillBounds::Bounds FillBounds::bounds(const Clear&) const { r eturn fCullRect; } // Ignores the clip.
219 template <> inline FillBounds::Bounds FillBounds::bounds(const DrawPaint&) const { return fCurrentClipBounds; }
220 template <> inline FillBounds::Bounds FillBounds::bounds(const NoOp&) const { r eturn Bounds::MakeEmpty(); } // NoOps don't draw.
221
222 template <> inline FillBounds::Bounds FillBounds::bounds(const DrawSprite& op) c onst {
223 // Ignores the matrix.
224 const SkBitmap& bm = op.bitmap;
225 return Bounds::MakeXYWH(SkIntToScalar(op.left), SkIntToScalar(op.top),
226 SkIntToScalar(bm.width()), SkIntToScalar(bm.height() ));
227 }
228
229 template <> inline FillBounds::Bounds FillBounds::bounds(const DrawRect& op) con st { return this->adjustAndMap(op.rect, &op.paint); }
230 template <> inline FillBounds::Bounds FillBounds::bounds(const DrawOval& op) con st { return this->adjustAndMap(op.oval, &op.paint); }
231 template <> inline FillBounds::Bounds FillBounds::bounds(const DrawRRect& op) co nst {
232 return this->adjustAndMap(op.rrect.rect(), &op.paint);
233 }
234 template <> inline FillBounds::Bounds FillBounds::bounds(const DrawDRRect& op) c onst {
235 return this->adjustAndMap(op.outer.rect(), &op.paint);
236 }
237 template <> inline FillBounds::Bounds FillBounds::bounds(const DrawImage& op) co nst {
238 const SkImage* image = op.image;
239 SkRect rect = SkRect::MakeXYWH(SkIntToScalar(op.left), SkIntToScalar(op.top) ,
240 SkIntToScalar(image->width()), SkIntToScalar( image->height()));
241
242 return this->adjustAndMap(rect, op.paint);
243 }
244 template <> inline FillBounds::Bounds FillBounds::bounds(const DrawImageRect& op ) const {
245 return this->adjustAndMap(op.dst, op.paint);
246 }
247 template <> inline FillBounds::Bounds FillBounds::bounds(const DrawBitmapRectToR ect& op) const {
248 return this->adjustAndMap(op.dst, op.paint);
249 }
250 template <> inline FillBounds::Bounds FillBounds::bounds(const DrawBitmapNine& o p) const {
251 return this->adjustAndMap(op.dst, op.paint);
252 }
253 template <> inline FillBounds::Bounds FillBounds::bounds(const DrawBitmap& op) c onst {
254 const SkBitmap& bm = op.bitmap;
255 return this->adjustAndMap(SkRect::MakeXYWH(SkIntToScalar(op.left),
256 SkIntToScalar(op.top),
257 SkIntToScalar(bm.width()),
258 SkIntToScalar(bm.height())),
259 op.paint);
260 }
261 template <> inline FillBounds::Bounds FillBounds::bounds(const DrawBitmapMatrix& op) const {
262 const SkBitmap& bm = op.bitmap;
263 SkRect dst = SkRect::MakeWH(SkIntToScalar(bm.width()),
264 SkIntToScalar(bm.height()));
265 op.matrix.mapRect(&dst);
266 return this->adjustAndMap(dst, op.paint);
267 }
268
269 template <> inline FillBounds::Bounds FillBounds::bounds(const DrawPath& op) con st {
270 return op.path.isInverseFillType() ? fCurrentClipBounds
271 : this->adjustAndMap(op.path.getBounds(), &op.paint);
272 }
273 template <> inline FillBounds::Bounds FillBounds::bounds(const DrawPoints& op) c onst {
274 SkRect dst;
275 dst.set(op.pts, op.count);
276
277 // Pad the bounding box a little to make sure hairline points' bounds aren't empty.
278 SkScalar stroke = SkMaxScalar(op.paint.getStrokeWidth(), 0.01f);
279 dst.outset(stroke/2, stroke/2);
280
281 return this->adjustAndMap(dst, &op.paint);
282 }
283 template <> inline FillBounds::Bounds FillBounds::bounds(const DrawPatch& op) co nst {
284 SkRect dst;
285 dst.set(op.cubics, SkPatchUtils::kNumCtrlPts);
286 return this->adjustAndMap(dst, &op.paint);
287 }
288 template <> inline FillBounds::Bounds FillBounds::bounds(const DrawVertices& op) const {
289 SkRect dst;
290 dst.set(op.vertices, op.vertexCount);
291 return this->adjustAndMap(dst, &op.paint);
292 }
293
294 template <> inline FillBounds::Bounds FillBounds::bounds(const DrawPicture& op) const {
295 SkRect dst = op.picture->cullRect();
296 if (op.matrix) {
297 op.matrix->mapRect(&dst);
298 }
299 return this->adjustAndMap(dst, op.paint);
300 }
301
302 template <> inline FillBounds::Bounds FillBounds::bounds(const DrawPosText& op) const {
303 const int N = op.paint.countText(op.text, op.byteLength);
304 if (N == 0) {
305 return Bounds::MakeEmpty();
306 }
307
308 SkRect dst;
309 dst.set(op.pos, N);
310 AdjustTextForFontMetrics(&dst, op.paint);
311 return this->adjustAndMap(dst, &op.paint);
312 }
313 template <> inline FillBounds::Bounds FillBounds::bounds(const DrawPosTextH& op) const {
314 const int N = op.paint.countText(op.text, op.byteLength);
315 if (N == 0) {
316 return Bounds::MakeEmpty();
317 }
318
319 SkScalar left = op.xpos[0], right = op.xpos[0];
320 for (int i = 1; i < N; i++) {
321 left = SkMinScalar(left, op.xpos[i]);
322 right = SkMaxScalar(right, op.xpos[i]);
323 }
324 SkRect dst = { left, op.y, right, op.y };
325 AdjustTextForFontMetrics(&dst, op.paint);
326 return this->adjustAndMap(dst, &op.paint);
327 }
328 template <> inline FillBounds::Bounds FillBounds::bounds(const DrawTextOnPath& o p) const {
329 SkRect dst = op.path.getBounds();
330
331 // Pad all sides by the maximum padding in any direction we'd normally apply .
332 SkRect pad = { 0, 0, 0, 0};
333 AdjustTextForFontMetrics(&pad, op.paint);
334
335 // That maximum padding happens to always be the right pad today.
336 SkASSERT(pad.fLeft == -pad.fRight);
337 SkASSERT(pad.fTop == -pad.fBottom);
338 SkASSERT(pad.fRight > pad.fBottom);
339 dst.outset(pad.fRight, pad.fRight);
340
341 return this->adjustAndMap(dst, &op.paint);
342 }
343
344 template <> inline FillBounds::Bounds FillBounds::bounds(const DrawTextBlob& op) const {
345 SkRect dst = op.blob->bounds();
346 dst.offset(op.x, op.y);
347 return this->adjustAndMap(dst, &op.paint);
348 }
349
77 } // namespace SkRecords 350 } // namespace SkRecords
78 351
79 #endif//SkRecordDraw_DEFINED 352 #endif//SkRecordDraw_DEFINED
OLDNEW
« no previous file with comments | « include/core/SkPicture.h ('k') | src/core/SkRecordDraw.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698