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 |
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 // 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. |
19 SkIRect query; | |
20 | |
21 // The SkRecord and BBH were recorded in identity space. This canvas | 19 // The SkRecord and BBH were recorded in identity space. This canvas |
22 // is not necessarily in that same space. getClipBounds() returns us | 20 // is not necessarily in that same space. getClipBounds() returns us |
23 // this canvas' clip bounds transformed back into identity space, which | 21 // this canvas' clip bounds transformed back into identity space, which |
24 // lets us query the BBH. | 22 // lets us query the BBH. |
25 SkRect clipBounds = { 0, 0, 0, 0 }; | 23 SkRect query = { 0, 0, 0, 0 }; |
26 (void)canvas->getClipBounds(&clipBounds); | 24 (void)canvas->getClipBounds(&query); |
27 clipBounds.roundOut(&query); | |
28 | 25 |
29 SkTDArray<void*> ops; | 26 SkTDArray<void*> ops; |
30 bbh->search(query, &ops); | 27 bbh->search(query, &ops); |
31 | 28 |
32 SkRecords::Draw draw(canvas); | 29 SkRecords::Draw draw(canvas); |
33 for (int i = 0; i < ops.count(); i++) { | 30 for (int i = 0; i < ops.count(); i++) { |
34 if (NULL != callback && callback->abortDrawing()) { | 31 if (NULL != callback && callback->abortDrawing()) { |
35 return; | 32 return; |
36 } | 33 } |
37 record.visit<void>((uintptr_t)ops[i], draw); // See FillBounds belo
w. | 34 record.visit<void>((uintptr_t)ops[i], draw); // See FillBounds belo
w. |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
116 // To implement this, we keep a stack of active Save blocks. As we consume ops | 113 // To implement this, we keep a stack of active Save blocks. As we consume ops |
117 // inside the Save/Restore block, drawing ops are unioned with the bounds of | 114 // inside the Save/Restore block, drawing ops are unioned with the bounds of |
118 // the block, and control ops are stashed away for later. When we finish the | 115 // the block, and control ops are stashed away for later. When we finish the |
119 // block with a Restore, our bounds are complete, and we go back and fill them | 116 // block with a Restore, our bounds are complete, and we go back and fill them |
120 // in for all the control ops we stashed away. | 117 // in for all the control ops we stashed away. |
121 class FillBounds : SkNoncopyable { | 118 class FillBounds : SkNoncopyable { |
122 public: | 119 public: |
123 FillBounds(const SkRecord& record, SkBBoxHierarchy* bbh) : fBounds(record.co
unt()) { | 120 FillBounds(const SkRecord& record, SkBBoxHierarchy* bbh) : fBounds(record.co
unt()) { |
124 // Calculate bounds for all ops. This won't go quite in order, so we'll
need | 121 // Calculate bounds for all ops. This won't go quite in order, so we'll
need |
125 // to store the bounds separately then feed them in to the BBH later in
order. | 122 // to store the bounds separately then feed them in to the BBH later in
order. |
126 const SkIRect largest = SkIRect::MakeLargest(); | 123 const Bounds largest = Bounds::MakeLargest(); |
127 fCTM = &SkMatrix::I(); | 124 fCTM = &SkMatrix::I(); |
128 fCurrentClipBounds = largest; | 125 fCurrentClipBounds = largest; |
129 for (fCurrentOp = 0; fCurrentOp < record.count(); fCurrentOp++) { | 126 for (fCurrentOp = 0; fCurrentOp < record.count(); fCurrentOp++) { |
130 record.visit<void>(fCurrentOp, *this); | 127 record.visit<void>(fCurrentOp, *this); |
131 } | 128 } |
132 | 129 |
133 // If we have any lingering unpaired Saves, simulate restores to make | 130 // If we have any lingering unpaired Saves, simulate restores to make |
134 // sure all ops in those Save blocks have their bounds calculated. | 131 // sure all ops in those Save blocks have their bounds calculated. |
135 while (!fSaveStack.isEmpty()) { | 132 while (!fSaveStack.isEmpty()) { |
136 this->popSaveBlock(); | 133 this->popSaveBlock(); |
(...skipping 14 matching lines...) Expand all Loading... |
151 bbh->flushDeferredInserts(); | 148 bbh->flushDeferredInserts(); |
152 } | 149 } |
153 | 150 |
154 template <typename T> void operator()(const T& op) { | 151 template <typename T> void operator()(const T& op) { |
155 this->updateCTM(op); | 152 this->updateCTM(op); |
156 this->updateClipBounds(op); | 153 this->updateClipBounds(op); |
157 this->trackBounds(op); | 154 this->trackBounds(op); |
158 } | 155 } |
159 | 156 |
160 private: | 157 private: |
| 158 // In this file, SkRect are in local coordinates, Bounds are translated back
to identity space. |
| 159 typedef SkRect Bounds; |
| 160 |
161 struct SaveBounds { | 161 struct SaveBounds { |
162 int controlOps; // Number of control ops in this Save block, incl
uding the Save. | 162 int controlOps; // Number of control ops in this Save block, incl
uding the Save. |
163 SkIRect bounds; // Bounds of everything in the block. | 163 Bounds bounds; // Bounds of everything in the block. |
164 const SkPaint* paint; // Unowned. If set, adjusts the bounds of all op
s in this block. | 164 const SkPaint* paint; // Unowned. If set, adjusts the bounds of all op
s in this block. |
165 }; | 165 }; |
166 | 166 |
167 template <typename T> void updateCTM(const T&) { /* most ops don't change th
e CTM */ } | 167 template <typename T> void updateCTM(const T&) { /* most ops don't change th
e CTM */ } |
168 void updateCTM(const Restore& op) { fCTM = &op.matrix; } | 168 void updateCTM(const Restore& op) { fCTM = &op.matrix; } |
169 void updateCTM(const SetMatrix& op) { fCTM = &op.matrix; } | 169 void updateCTM(const SetMatrix& op) { fCTM = &op.matrix; } |
170 | 170 |
171 template <typename T> void updateClipBounds(const T&) { /* most ops don't ch
ange the clip */ } | 171 template <typename T> void updateClipBounds(const T&) { /* most ops don't ch
ange the clip */ } |
172 // Each of these devBounds fields is the state of the device bounds after th
e op. | 172 // Each of these devBounds fields is the state of the device bounds after th
e op. |
173 // So Restore's devBounds are those bounds saved by its paired Save or SaveL
ayer. | 173 // So Restore's devBounds are those bounds saved by its paired Save or SaveL
ayer. |
174 void updateClipBounds(const Restore& op) { fCurrentClipBounds = op.devBou
nds; } | 174 void updateClipBounds(const Restore& op) { fCurrentClipBounds = Bounds::M
ake(op.devBounds); } |
175 void updateClipBounds(const ClipPath& op) { fCurrentClipBounds = op.devBou
nds; } | 175 void updateClipBounds(const ClipPath& op) { fCurrentClipBounds = Bounds::M
ake(op.devBounds); } |
176 void updateClipBounds(const ClipRRect& op) { fCurrentClipBounds = op.devBou
nds; } | 176 void updateClipBounds(const ClipRRect& op) { fCurrentClipBounds = Bounds::M
ake(op.devBounds); } |
177 void updateClipBounds(const ClipRect& op) { fCurrentClipBounds = op.devBou
nds; } | 177 void updateClipBounds(const ClipRect& op) { fCurrentClipBounds = Bounds::M
ake(op.devBounds); } |
178 void updateClipBounds(const ClipRegion& op) { fCurrentClipBounds = op.devBou
nds; } | 178 void updateClipBounds(const ClipRegion& op) { fCurrentClipBounds = Bounds::M
ake(op.devBounds); } |
179 void updateClipBounds(const SaveLayer& op) { | 179 void updateClipBounds(const SaveLayer& op) { |
180 if (op.bounds) { | 180 if (op.bounds) { |
181 fCurrentClipBounds.intersect(this->adjustAndMap(*op.bounds, op.paint
)); | 181 fCurrentClipBounds.intersect(this->adjustAndMap(*op.bounds, op.paint
)); |
182 } | 182 } |
183 } | 183 } |
184 | 184 |
185 // The bounds of these ops must be calculated when we hit the Restore | 185 // The bounds of these ops must be calculated when we hit the Restore |
186 // from the bounds of the ops in the same Save block. | 186 // from the bounds of the ops in the same Save block. |
187 void trackBounds(const Save&) { this->pushSaveBlock(NULL); } | 187 void trackBounds(const Save&) { this->pushSaveBlock(NULL); } |
188 void trackBounds(const SaveLayer& op) { this->pushSaveBlock(op.paint); } | 188 void trackBounds(const SaveLayer& op) { this->pushSaveBlock(op.paint); } |
(...skipping 11 matching lines...) Expand all Loading... |
200 void trackBounds(const EndCommentGroup&) { this->pushControl(); } | 200 void trackBounds(const EndCommentGroup&) { this->pushControl(); } |
201 | 201 |
202 // For all other ops, we can calculate and store the bounds directly now. | 202 // For all other ops, we can calculate and store the bounds directly now. |
203 template <typename T> void trackBounds(const T& op) { | 203 template <typename T> void trackBounds(const T& op) { |
204 fBounds[fCurrentOp] = this->bounds(op); | 204 fBounds[fCurrentOp] = this->bounds(op); |
205 this->updateSaveBounds(fBounds[fCurrentOp]); | 205 this->updateSaveBounds(fBounds[fCurrentOp]); |
206 } | 206 } |
207 | 207 |
208 void pushSaveBlock(const SkPaint* paint) { | 208 void pushSaveBlock(const SkPaint* paint) { |
209 // Starting a new Save block. Push a new entry to represent that. | 209 // Starting a new Save block. Push a new entry to represent that. |
210 SaveBounds sb = { 0, SkIRect::MakeEmpty(), paint }; | 210 SaveBounds sb = { 0, Bounds::MakeEmpty(), paint }; |
211 fSaveStack.push(sb); | 211 fSaveStack.push(sb); |
212 this->pushControl(); | 212 this->pushControl(); |
213 } | 213 } |
214 | 214 |
215 static bool PaintMayAffectTransparentBlack(const SkPaint* paint) { | 215 static bool PaintMayAffectTransparentBlack(const SkPaint* paint) { |
216 // FIXME: this is very conservative | 216 // FIXME: this is very conservative |
217 return paint && (paint->getImageFilter() || paint->getColorFilter()); | 217 return paint && (paint->getImageFilter() || paint->getColorFilter()); |
218 } | 218 } |
219 | 219 |
220 SkIRect popSaveBlock() { | 220 Bounds popSaveBlock() { |
221 // We're done the Save block. Apply the block's bounds to all control o
ps inside it. | 221 // We're done the Save block. Apply the block's bounds to all control o
ps inside it. |
222 SaveBounds sb; | 222 SaveBounds sb; |
223 fSaveStack.pop(&sb); | 223 fSaveStack.pop(&sb); |
224 | 224 |
225 // If the paint affects transparent black, we can't trust any of our cal
culated bounds. | 225 // If the paint affects transparent black, we can't trust any of our cal
culated bounds. |
226 const SkIRect& bounds = | 226 const Bounds& bounds = |
227 PaintMayAffectTransparentBlack(sb.paint) ? fCurrentClipBounds : sb.b
ounds; | 227 PaintMayAffectTransparentBlack(sb.paint) ? fCurrentClipBounds : sb.b
ounds; |
228 | 228 |
229 while (sb.controlOps --> 0) { | 229 while (sb.controlOps --> 0) { |
230 this->popControl(bounds); | 230 this->popControl(bounds); |
231 } | 231 } |
232 | 232 |
233 // This whole Save block may be part another Save block. | 233 // This whole Save block may be part another Save block. |
234 this->updateSaveBounds(bounds); | 234 this->updateSaveBounds(bounds); |
235 | 235 |
236 // If called from a real Restore (not a phony one for balance), it'll ne
ed the bounds. | 236 // If called from a real Restore (not a phony one for balance), it'll ne
ed the bounds. |
237 return bounds; | 237 return bounds; |
238 } | 238 } |
239 | 239 |
240 void pushControl() { | 240 void pushControl() { |
241 fControlIndices.push(fCurrentOp); | 241 fControlIndices.push(fCurrentOp); |
242 if (!fSaveStack.isEmpty()) { | 242 if (!fSaveStack.isEmpty()) { |
243 fSaveStack.top().controlOps++; | 243 fSaveStack.top().controlOps++; |
244 } | 244 } |
245 } | 245 } |
246 | 246 |
247 void popControl(const SkIRect& bounds) { | 247 void popControl(const Bounds& bounds) { |
248 fBounds[fControlIndices.top()] = bounds; | 248 fBounds[fControlIndices.top()] = bounds; |
249 fControlIndices.pop(); | 249 fControlIndices.pop(); |
250 } | 250 } |
251 | 251 |
252 void updateSaveBounds(const SkIRect& bounds) { | 252 void updateSaveBounds(const Bounds& bounds) { |
253 // If we're in a Save block, expand its bounds to cover these bounds too
. | 253 // If we're in a Save block, expand its bounds to cover these bounds too
. |
254 if (!fSaveStack.isEmpty()) { | 254 if (!fSaveStack.isEmpty()) { |
255 fSaveStack.top().bounds.join(bounds); | 255 fSaveStack.top().bounds.join(bounds); |
256 } | 256 } |
257 } | 257 } |
258 | 258 |
259 // FIXME: this method could use better bounds | 259 // FIXME: this method could use better bounds |
260 SkIRect bounds(const DrawText&) const { return fCurrentClipBounds; } | 260 Bounds bounds(const DrawText&) const { return fCurrentClipBounds; } |
261 | 261 |
262 SkIRect bounds(const Clear&) const { return SkIRect::MakeLargest(); } // Ig
nores the clip. | 262 Bounds bounds(const Clear&) const { return Bounds::MakeLargest(); } // Igno
res the clip. |
263 SkIRect bounds(const DrawPaint&) const { return fCurrentClipBounds; } | 263 Bounds bounds(const DrawPaint&) const { return fCurrentClipBounds; } |
264 SkIRect bounds(const NoOp&) const { return SkIRect::MakeEmpty(); } // No
Ops don't draw. | 264 Bounds bounds(const NoOp&) const { return Bounds::MakeEmpty(); } // NoOp
s don't draw. |
265 | 265 |
266 SkIRect bounds(const DrawSprite& op) const { | 266 Bounds bounds(const DrawSprite& op) const { |
267 const SkBitmap& bm = op.bitmap; | 267 const SkBitmap& bm = op.bitmap; |
268 return SkIRect::MakeXYWH(op.left, op.top, bm.width(), bm.height()); //
Ignores the matrix. | 268 return Bounds::MakeXYWH(op.left, op.top, bm.width(), bm.height()); // I
gnores the matrix. |
269 } | 269 } |
270 | 270 |
271 SkIRect bounds(const DrawRect& op) const { return this->adjustAndMap(op.rect
, &op.paint); } | 271 Bounds bounds(const DrawRect& op) const { return this->adjustAndMap(op.rect,
&op.paint); } |
272 SkIRect bounds(const DrawOval& op) const { return this->adjustAndMap(op.oval
, &op.paint); } | 272 Bounds bounds(const DrawOval& op) const { return this->adjustAndMap(op.oval,
&op.paint); } |
273 SkIRect bounds(const DrawRRect& op) const { | 273 Bounds bounds(const DrawRRect& op) const { |
274 return this->adjustAndMap(op.rrect.rect(), &op.paint); | 274 return this->adjustAndMap(op.rrect.rect(), &op.paint); |
275 } | 275 } |
276 SkIRect bounds(const DrawDRRect& op) const { | 276 Bounds bounds(const DrawDRRect& op) const { |
277 return this->adjustAndMap(op.outer.rect(), &op.paint); | 277 return this->adjustAndMap(op.outer.rect(), &op.paint); |
278 } | 278 } |
279 | 279 |
280 SkIRect bounds(const DrawBitmapRectToRect& op) const { | 280 Bounds bounds(const DrawBitmapRectToRect& op) const { |
281 return this->adjustAndMap(op.dst, op.paint); | 281 return this->adjustAndMap(op.dst, op.paint); |
282 } | 282 } |
283 SkIRect bounds(const DrawBitmapNine& op) const { | 283 Bounds bounds(const DrawBitmapNine& op) const { |
284 return this->adjustAndMap(op.dst, op.paint); | 284 return this->adjustAndMap(op.dst, op.paint); |
285 } | 285 } |
286 SkIRect bounds(const DrawBitmap& op) const { | 286 Bounds bounds(const DrawBitmap& op) const { |
287 const SkBitmap& bm = op.bitmap; | 287 const SkBitmap& bm = op.bitmap; |
288 return this->adjustAndMap(SkRect::MakeXYWH(op.left, op.top, bm.width(),
bm.height()), | 288 return this->adjustAndMap(SkRect::MakeXYWH(op.left, op.top, bm.width(),
bm.height()), |
289 op.paint); | 289 op.paint); |
290 } | 290 } |
291 SkIRect bounds(const DrawBitmapMatrix& op) const { | 291 Bounds bounds(const DrawBitmapMatrix& op) const { |
292 const SkBitmap& bm = op.bitmap; | 292 const SkBitmap& bm = op.bitmap; |
293 SkRect dst = SkRect::MakeWH(bm.width(), bm.height()); | 293 SkRect dst = SkRect::MakeWH(bm.width(), bm.height()); |
294 op.matrix.mapRect(&dst); | 294 op.matrix.mapRect(&dst); |
295 return this->adjustAndMap(dst, op.paint); | 295 return this->adjustAndMap(dst, op.paint); |
296 } | 296 } |
297 | 297 |
298 SkIRect bounds(const DrawPath& op) const { | 298 Bounds bounds(const DrawPath& op) const { |
299 return op.path.isInverseFillType() ? fCurrentClipBounds | 299 return op.path.isInverseFillType() ? fCurrentClipBounds |
300 : this->adjustAndMap(op.path.getBound
s(), &op.paint); | 300 : this->adjustAndMap(op.path.getBound
s(), &op.paint); |
301 } | 301 } |
302 SkIRect bounds(const DrawPoints& op) const { | 302 Bounds bounds(const DrawPoints& op) const { |
303 SkRect dst; | 303 SkRect dst; |
304 dst.set(op.pts, op.count); | 304 dst.set(op.pts, op.count); |
305 | 305 |
306 // Pad the bounding box a little to make sure hairline points' bounds ar
en't empty. | 306 // Pad the bounding box a little to make sure hairline points' bounds ar
en't empty. |
307 SkScalar stroke = SkMaxScalar(op.paint.getStrokeWidth(), 0.01f); | 307 SkScalar stroke = SkMaxScalar(op.paint.getStrokeWidth(), 0.01f); |
308 dst.outset(stroke/2, stroke/2); | 308 dst.outset(stroke/2, stroke/2); |
309 | 309 |
310 return this->adjustAndMap(dst, &op.paint); | 310 return this->adjustAndMap(dst, &op.paint); |
311 } | 311 } |
312 SkIRect bounds(const DrawPatch& op) const { | 312 Bounds bounds(const DrawPatch& op) const { |
313 SkRect dst; | 313 SkRect dst; |
314 dst.set(op.cubics, SkPatchUtils::kNumCtrlPts); | 314 dst.set(op.cubics, SkPatchUtils::kNumCtrlPts); |
315 return this->adjustAndMap(dst, &op.paint); | 315 return this->adjustAndMap(dst, &op.paint); |
316 } | 316 } |
317 SkIRect bounds(const DrawVertices& op) const { | 317 Bounds bounds(const DrawVertices& op) const { |
318 SkRect dst; | 318 SkRect dst; |
319 dst.set(op.vertices, op.vertexCount); | 319 dst.set(op.vertices, op.vertexCount); |
320 return this->adjustAndMap(dst, &op.paint); | 320 return this->adjustAndMap(dst, &op.paint); |
321 } | 321 } |
322 | 322 |
323 SkIRect bounds(const DrawPicture& op) const { | 323 Bounds bounds(const DrawPicture& op) const { |
324 SkRect dst = SkRect::MakeWH(op.picture->width(), op.picture->height()); | 324 SkRect dst = SkRect::MakeWH(op.picture->width(), op.picture->height()); |
325 if (op.matrix) { | 325 if (op.matrix) { |
326 op.matrix->mapRect(&dst); | 326 op.matrix->mapRect(&dst); |
327 } | 327 } |
328 return this->adjustAndMap(dst, op.paint); | 328 return this->adjustAndMap(dst, op.paint); |
329 } | 329 } |
330 | 330 |
331 SkIRect bounds(const DrawPosText& op) const { | 331 Bounds bounds(const DrawPosText& op) const { |
332 const int N = op.paint.countText(op.text, op.byteLength); | 332 const int N = op.paint.countText(op.text, op.byteLength); |
333 if (N == 0) { | 333 if (N == 0) { |
334 return SkIRect::MakeEmpty(); | 334 return Bounds::MakeEmpty(); |
335 } | 335 } |
336 | 336 |
337 SkRect dst; | 337 SkRect dst; |
338 dst.set(op.pos, op.paint.countText(op.text, N)); | 338 dst.set(op.pos, op.paint.countText(op.text, N)); |
339 AdjustTextForFontMetrics(&dst, op.paint); | 339 AdjustTextForFontMetrics(&dst, op.paint); |
340 return this->adjustAndMap(dst, &op.paint); | 340 return this->adjustAndMap(dst, &op.paint); |
341 } | 341 } |
342 SkIRect bounds(const DrawPosTextH& op) const { | 342 Bounds bounds(const DrawPosTextH& op) const { |
343 const int N = op.paint.countText(op.text, op.byteLength); | 343 const int N = op.paint.countText(op.text, op.byteLength); |
344 if (N == 0) { | 344 if (N == 0) { |
345 return SkIRect::MakeEmpty(); | 345 return Bounds::MakeEmpty(); |
346 } | 346 } |
347 | 347 |
348 SkScalar left = op.xpos[0], right = op.xpos[0]; | 348 SkScalar left = op.xpos[0], right = op.xpos[0]; |
349 for (int i = 1; i < N; i++) { | 349 for (int i = 1; i < N; i++) { |
350 left = SkMinScalar(left, op.xpos[i]); | 350 left = SkMinScalar(left, op.xpos[i]); |
351 right = SkMaxScalar(right, op.xpos[i]); | 351 right = SkMaxScalar(right, op.xpos[i]); |
352 } | 352 } |
353 SkRect dst = { left, op.y, right, op.y }; | 353 SkRect dst = { left, op.y, right, op.y }; |
354 AdjustTextForFontMetrics(&dst, op.paint); | 354 AdjustTextForFontMetrics(&dst, op.paint); |
355 return this->adjustAndMap(dst, &op.paint); | 355 return this->adjustAndMap(dst, &op.paint); |
356 } | 356 } |
357 SkIRect bounds(const DrawTextOnPath& op) const { | 357 Bounds bounds(const DrawTextOnPath& op) const { |
358 SkRect dst = op.path.getBounds(); | 358 SkRect dst = op.path.getBounds(); |
359 | 359 |
360 // Pad all sides by the maximum padding in any direction we'd normally a
pply. | 360 // Pad all sides by the maximum padding in any direction we'd normally a
pply. |
361 SkRect pad = { 0, 0, 0, 0}; | 361 SkRect pad = { 0, 0, 0, 0}; |
362 AdjustTextForFontMetrics(&pad, op.paint); | 362 AdjustTextForFontMetrics(&pad, op.paint); |
363 | 363 |
364 // That maximum padding happens to always be the right pad today. | 364 // That maximum padding happens to always be the right pad today. |
365 SkASSERT(pad.fLeft == -pad.fRight); | 365 SkASSERT(pad.fLeft == -pad.fRight); |
366 SkASSERT(pad.fTop == -pad.fBottom); | 366 SkASSERT(pad.fTop == -pad.fBottom); |
367 SkASSERT(pad.fRight > pad.fBottom); | 367 SkASSERT(pad.fRight > pad.fBottom); |
368 dst.outset(pad.fRight, pad.fRight); | 368 dst.outset(pad.fRight, pad.fRight); |
369 | 369 |
370 return this->adjustAndMap(dst, &op.paint); | 370 return this->adjustAndMap(dst, &op.paint); |
371 } | 371 } |
372 | 372 |
373 SkIRect bounds(const DrawTextBlob& op) const { | 373 Bounds bounds(const DrawTextBlob& op) const { |
374 SkRect dst = op.blob->bounds(); | 374 SkRect dst = op.blob->bounds(); |
375 dst.offset(op.x, op.y); | 375 dst.offset(op.x, op.y); |
376 // TODO: remove when implicit bounds are plumbed through | 376 // TODO: remove when implicit bounds are plumbed through |
377 if (dst.isEmpty()) { | 377 if (dst.isEmpty()) { |
378 return fCurrentClipBounds; | 378 return fCurrentClipBounds; |
379 } | 379 } |
380 return this->adjustAndMap(dst, &op.paint); | 380 return this->adjustAndMap(dst, &op.paint); |
381 } | 381 } |
382 | 382 |
383 static void AdjustTextForFontMetrics(SkRect* rect, const SkPaint& paint) { | 383 static void AdjustTextForFontMetrics(SkRect* rect, const SkPaint& paint) { |
(...skipping 24 matching lines...) Expand all Loading... |
408 if (paint) { | 408 if (paint) { |
409 if (paint->canComputeFastBounds()) { | 409 if (paint->canComputeFastBounds()) { |
410 *rect = paint->computeFastBounds(*rect, rect); | 410 *rect = paint->computeFastBounds(*rect, rect); |
411 return true; | 411 return true; |
412 } | 412 } |
413 return false; | 413 return false; |
414 } | 414 } |
415 return true; | 415 return true; |
416 } | 416 } |
417 | 417 |
418 // Adjust rect for all paints that may affect its geometry, then map it to d
evice space. | 418 // Adjust rect for all paints that may affect its geometry, then map it to i
dentity space. |
419 SkIRect adjustAndMap(SkRect rect, const SkPaint* paint) const { | 419 Bounds adjustAndMap(SkRect rect, const SkPaint* paint) const { |
420 // Inverted rectangles really confuse our BBHs. | 420 // Inverted rectangles really confuse our BBHs. |
421 rect.sort(); | 421 rect.sort(); |
422 | 422 |
423 // Adjust the rect for its own paint. | 423 // Adjust the rect for its own paint. |
424 if (!AdjustForPaint(paint, &rect)) { | 424 if (!AdjustForPaint(paint, &rect)) { |
425 // The paint could do anything to our bounds. The only safe answer
is the current clip. | 425 // The paint could do anything to our bounds. The only safe answer
is the current clip. |
426 return fCurrentClipBounds; | 426 return fCurrentClipBounds; |
427 } | 427 } |
428 | 428 |
429 // Adjust rect for all the paints from the SaveLayers we're inside. | 429 // Adjust rect for all the paints from the SaveLayers we're inside. |
430 for (int i = fSaveStack.count() - 1; i >= 0; i--) { | 430 for (int i = fSaveStack.count() - 1; i >= 0; i--) { |
431 if (!AdjustForPaint(fSaveStack[i].paint, &rect)) { | 431 if (!AdjustForPaint(fSaveStack[i].paint, &rect)) { |
432 // Same deal as above. | 432 // Same deal as above. |
433 return fCurrentClipBounds; | 433 return fCurrentClipBounds; |
434 } | 434 } |
435 } | 435 } |
436 | 436 |
437 // Map the rect back to device space. | 437 // Map the rect back to identity space. |
438 fCTM->mapRect(&rect); | 438 fCTM->mapRect(&rect); |
439 SkIRect devRect; | |
440 rect.roundOut(&devRect); | |
441 | 439 |
442 // Nothing can draw outside the current clip. | 440 // Nothing can draw outside the current clip. |
443 // (Only bounded ops call into this method, so oddballs like Clear don't
matter here.) | 441 // (Only bounded ops call into this method, so oddballs like Clear don't
matter here.) |
444 devRect.intersect(fCurrentClipBounds); | 442 rect.intersect(fCurrentClipBounds); |
445 return devRect; | 443 return rect; |
446 } | 444 } |
447 | 445 |
448 // Conservative device bounds for each op in the SkRecord. | 446 // Conservative identity-space bounds for each op in the SkRecord. |
449 SkAutoTMalloc<SkIRect> fBounds; | 447 SkAutoTMalloc<Bounds> fBounds; |
450 | 448 |
451 // We walk fCurrentOp through the SkRecord, as we go using updateCTM() | 449 // We walk fCurrentOp through the SkRecord, as we go using updateCTM() |
452 // and updateClipBounds() to maintain the exact CTM (fCTM) and conservative | 450 // and updateClipBounds() to maintain the exact CTM (fCTM) and conservative |
453 // device bounds of the current clip (fCurrentClipBounds). | 451 // identity-space bounds of the current clip (fCurrentClipBounds). |
454 unsigned fCurrentOp; | 452 unsigned fCurrentOp; |
455 const SkMatrix* fCTM; | 453 const SkMatrix* fCTM; |
456 SkIRect fCurrentClipBounds; | 454 Bounds fCurrentClipBounds; |
457 | 455 |
458 // Used to track the bounds of Save/Restore blocks and the control ops insid
e them. | 456 // Used to track the bounds of Save/Restore blocks and the control ops insid
e them. |
459 SkTDArray<SaveBounds> fSaveStack; | 457 SkTDArray<SaveBounds> fSaveStack; |
460 SkTDArray<unsigned> fControlIndices; | 458 SkTDArray<unsigned> fControlIndices; |
461 }; | 459 }; |
462 | 460 |
463 } // namespace SkRecords | 461 } // namespace SkRecords |
464 | 462 |
465 void SkRecordFillBounds(const SkRecord& record, SkBBoxHierarchy* bbh) { | 463 void SkRecordFillBounds(const SkRecord& record, SkBBoxHierarchy* bbh) { |
466 SkRecords::FillBounds(record, bbh); | 464 SkRecords::FillBounds(record, bbh); |
467 } | 465 } |
OLD | NEW |