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 "GrPictureUtils.h" | 8 #include "GrPictureUtils.h" |
9 | 9 |
10 #include "SkPaintPriv.h" | 10 #include "SkPaintPriv.h" |
| 11 #include "SkPatchUtils.h" |
11 #include "SkRecord.h" | 12 #include "SkRecord.h" |
12 #include "SkRecords.h" | 13 #include "SkRecords.h" |
13 | 14 |
14 SkPicture::AccelData::Key GrAccelData::ComputeAccelDataKey() { | 15 SkPicture::AccelData::Key GrAccelData::ComputeAccelDataKey() { |
15 static const SkPicture::AccelData::Key gGPUID = SkPicture::AccelData::Genera
teDomain(); | 16 static const SkPicture::AccelData::Key gGPUID = SkPicture::AccelData::Genera
teDomain(); |
16 | 17 |
17 return gGPUID; | 18 return gGPUID; |
18 } | 19 } |
19 | 20 |
| 21 // This looks silly, I know. Why not just use SkRect::MakeLargest()? |
| 22 // In practice, this is well large enough, and it has a few extra advantages: |
| 23 // it fits in an SkIRect, and we can munge it a little in both SkRect and |
| 24 // SKIRect space without worrying about overflow. |
| 25 static const SkRect kUnbounded = { -2e9f, -2e9f, 2e9f, 2e9f }; |
| 26 |
| 27 namespace SkRecords { |
| 28 |
20 // SkRecord visitor to gather saveLayer/restore information. | 29 // SkRecord visitor to gather saveLayer/restore information. |
21 class CollectLayers { | 30 class CollectLayers : SkNoncopyable { |
22 public: | 31 public: |
23 CollectLayers(const SkPicture* pict, GrAccelData* accelData) | 32 CollectLayers(const SkPicture* pict, GrAccelData* accelData) |
24 : fPictureID(pict->uniqueID()) | 33 : fPictureID(pict->uniqueID()) |
25 , fCTM(&SkMatrix::I()) | |
26 , fSaveLayersInStack(0) | 34 , fSaveLayersInStack(0) |
27 , fAccelData(accelData) { | 35 , fAccelData(accelData) { |
28 | 36 |
29 pict->cullRect().roundOut(&fCurrentClipBounds); | 37 // Calculate bounds for all ops. This won't go quite in order, so we'll
need |
| 38 // to store the bounds separately then feed them in to the BBH later in
order. |
| 39 fCTM = &SkMatrix::I(); |
| 40 fCurrentClipBounds = kUnbounded; |
30 | 41 |
31 if (NULL == pict->fRecord.get()) { | 42 if (NULL == pict->fRecord.get()) { |
32 return; | 43 return; |
33 } | 44 } |
34 | 45 |
| 46 fBounds.reset(pict->fRecord->count()); |
| 47 |
35 for (fCurrentOp = 0; fCurrentOp < pict->fRecord->count(); ++fCurrentOp)
{ | 48 for (fCurrentOp = 0; fCurrentOp < pict->fRecord->count(); ++fCurrentOp)
{ |
36 pict->fRecord->visit<void>(fCurrentOp, *this); | 49 pict->fRecord->visit<void>(fCurrentOp, *this); |
37 } | 50 } |
38 | 51 |
| 52 // If we have any lingering unpaired Saves, simulate restores to make |
| 53 // sure all ops in those Save blocks have their bounds calculated. |
39 while (!fSaveStack.isEmpty()) { | 54 while (!fSaveStack.isEmpty()) { |
40 this->popSaveBlock(); | 55 this->popSaveBlock(); |
41 } | 56 } |
| 57 |
| 58 // Any control ops not part of any Save/Restore block draw everywhere. |
| 59 while (!fControlIndices.isEmpty()) { |
| 60 this->popControl(kUnbounded); |
| 61 } |
| 62 |
| 63 //--------- LAYER HOISTING |
| 64 while (!fSaveLayerStack.isEmpty()) { |
| 65 this->popSaveLayerInfo(); |
| 66 } |
| 67 //--------- LAYER HOISTING |
42 } | 68 } |
43 | 69 |
44 template <typename T> void operator()(const T& op) { | 70 template <typename T> void operator()(const T& op) { |
45 this->updateCTM(op); | 71 this->updateCTM(op); |
46 this->updateClipBounds(op); | 72 this->updateClipBounds(op); |
| 73 this->trackBounds(op); |
| 74 //--------- LAYER HOISTING |
47 this->trackSaveLayers(op); | 75 this->trackSaveLayers(op); |
| 76 //--------- LAYER HOISTING |
48 } | 77 } |
49 | 78 |
50 private: | 79 private: |
51 | 80 // In this file, SkRect are in local coordinates, Bounds are translated back
to identity space. |
52 class SaveInfo { | 81 typedef SkRect Bounds; |
| 82 |
| 83 struct SaveBounds { |
| 84 int controlOps; // Number of control ops in this Save block, incl
uding the Save. |
| 85 Bounds bounds; // Bounds of everything in the block. |
| 86 const SkPaint* paint; // Unowned. If set, adjusts the bounds of all op
s in this block. |
| 87 }; |
| 88 |
| 89 //--------- LAYER HOISTING |
| 90 class SaveLayerInfo { |
53 public: | 91 public: |
54 SaveInfo() { } | 92 SaveLayerInfo() { } |
55 SaveInfo(int opIndex, bool isSaveLayer, const SkPaint* paint, const SkIR
ect& bounds) | 93 SaveLayerInfo(int opIndex, bool isSaveLayer, const SkPaint* paint, const
Bounds& clipBound) |
56 : fStartIndex(opIndex) | 94 : fStartIndex(opIndex) |
57 , fIsSaveLayer(isSaveLayer) | 95 , fIsSaveLayer(isSaveLayer) |
58 , fHasNestedSaveLayer(false) | 96 , fHasNestedSaveLayer(false) |
59 , fPaint(paint) | 97 , fPaint(paint) |
60 , fBounds(bounds) { | 98 , fClipBound(clipBound) { |
61 | |
62 } | 99 } |
63 | 100 |
64 int fStartIndex; | 101 int fStartIndex; |
65 bool fIsSaveLayer; | 102 bool fIsSaveLayer; |
66 bool fHasNestedSaveLayer; | 103 bool fHasNestedSaveLayer; |
67 const SkPaint* fPaint; | 104 const SkPaint* fPaint; |
68 SkIRect fBounds; | 105 Bounds fClipBound; |
69 }; | 106 }; |
70 | 107 //--------- LAYER HOISTING |
71 uint32_t fPictureID; | 108 |
72 unsigned int fCurrentOp; | 109 // Only Restore and SetMatrix change the CTM. |
73 const SkMatrix* fCTM; | 110 template <typename T> void updateCTM(const T&) {} |
74 SkIRect fCurrentClipBounds; | 111 void updateCTM(const Restore& op) { fCTM = &op.matrix; } |
75 int fSaveLayersInStack; | 112 void updateCTM(const SetMatrix& op) { fCTM = &op.matrix; } |
76 SkTDArray<SaveInfo> fSaveStack; | 113 |
77 GrAccelData* fAccelData; | 114 // Most ops don't change the clip. |
78 | 115 template <typename T> void updateClipBounds(const T&) {} |
79 template <typename T> void updateCTM(const T&) { /* most ops don't change th
e CTM */ } | 116 |
80 void updateCTM(const SkRecords::Restore& op) { fCTM = &op.matrix; } | 117 // Clip{Path,RRect,Rect,Region} obviously change the clip. They all know th
eir bounds already. |
81 void updateCTM(const SkRecords::SetMatrix& op) { fCTM = &op.matrix; } | 118 void updateClipBounds(const ClipPath& op) { this->updateClipBoundsForClipO
p(op.devBounds); } |
82 | 119 void updateClipBounds(const ClipRRect& op) { this->updateClipBoundsForClipO
p(op.devBounds); } |
83 template <typename T> void updateClipBounds(const T&) { /* most ops don't ch
ange the clip */ } | 120 void updateClipBounds(const ClipRect& op) { this->updateClipBoundsForClipO
p(op.devBounds); } |
84 // Each of these devBounds fields is the state of the device bounds after th
e op. | 121 void updateClipBounds(const ClipRegion& op) { this->updateClipBoundsForClipO
p(op.devBounds); } |
85 // So Restore's devBounds are those bounds saved by its paired Save or SaveL
ayer. | 122 |
86 void updateClipBounds(const SkRecords::Restore& op) { fCurrentClipBounds
= op.devBounds; } | 123 // The bounds of clip ops need to be adjusted for the paints of saveLayers t
hey're inside. |
87 void updateClipBounds(const SkRecords::ClipPath& op) { fCurrentClipBounds
= op.devBounds; } | 124 void updateClipBoundsForClipOp(const SkIRect& devBounds) { |
88 void updateClipBounds(const SkRecords::ClipRRect& op) { fCurrentClipBounds
= op.devBounds; } | 125 Bounds clip = SkRect::Make(devBounds); |
89 void updateClipBounds(const SkRecords::ClipRect& op) { fCurrentClipBounds
= op.devBounds; } | 126 // We don't call adjustAndMap() because as its last step it would inters
ect the adjusted |
90 void updateClipBounds(const SkRecords::ClipRegion& op) { fCurrentClipBounds
= op.devBounds; } | 127 // clip bounds with the previous clip, exactly what we can't do when the
clip grows. |
91 void updateClipBounds(const SkRecords::SaveLayer& op) { | 128 fCurrentClipBounds = this->adjustForSaveLayerPaints(&clip) ? clip : kUnb
ounded; |
| 129 } |
| 130 |
| 131 // Restore holds the devBounds for the clip after the {save,saveLayer}/resto
re block completes. |
| 132 void updateClipBounds(const Restore& op) { |
| 133 // This is just like the clip ops above, but we need to skip the effects
(if any) of our |
| 134 // paired saveLayer (if it is one); it has not yet been popped off the s
ave stack. Our |
| 135 // devBounds reflect the state of the world after the saveLayer/restore
block is done, |
| 136 // so they are not affected by the saveLayer's paint. |
| 137 const int kSavesToIgnore = 1; |
| 138 Bounds clip = SkRect::Make(op.devBounds); |
| 139 fCurrentClipBounds = |
| 140 this->adjustForSaveLayerPaints(&clip, kSavesToIgnore) ? clip : kUnbo
unded; |
| 141 } |
| 142 |
| 143 // We also take advantage of SaveLayer bounds when present to further cut th
e clip down. |
| 144 void updateClipBounds(const SaveLayer& op) { |
92 if (op.bounds) { | 145 if (op.bounds) { |
93 fCurrentClipBounds.intersect(this->adjustAndMap(*op.bounds, op.paint
)); | 146 // adjustAndMap() intersects these layer bounds with the previous cl
ip for us. |
94 } | 147 fCurrentClipBounds = this->adjustAndMap(*op.bounds, op.paint); |
95 } | 148 } |
96 | 149 } |
97 template <typename T> void trackSaveLayers(const T& op) { | 150 |
98 /* most ops aren't involved in saveLayers */ | 151 // The bounds of these ops must be calculated when we hit the Restore |
99 } | 152 // from the bounds of the ops in the same Save block. |
100 void trackSaveLayers(const SkRecords::Save& s) { this->pushSaveBlock(); } | 153 void trackBounds(const Save&) { this->pushSaveBlock(NULL); } |
101 void trackSaveLayers(const SkRecords::SaveLayer& sl) { this->pushSaveLayerBl
ock(sl.paint); } | 154 void trackBounds(const SaveLayer& op) { this->pushSaveBlock(op.paint); } |
102 void trackSaveLayers(const SkRecords::Restore& r) { this->popSaveBlock(); } | 155 void trackBounds(const Restore&) { fBounds[fCurrentOp] = this->popSaveBlock(
); } |
103 void trackSaveLayers(const SkRecords::DrawPicture& dp) { | 156 |
| 157 void trackBounds(const SetMatrix&) { this->pushControl(); } |
| 158 void trackBounds(const ClipRect&) { this->pushControl(); } |
| 159 void trackBounds(const ClipRRect&) { this->pushControl(); } |
| 160 void trackBounds(const ClipPath&) { this->pushControl(); } |
| 161 void trackBounds(const ClipRegion&) { this->pushControl(); } |
| 162 void trackBounds(const PushCull&) { this->pushControl(); } |
| 163 void trackBounds(const PopCull&) { this->pushControl(); } |
| 164 void trackBounds(const BeginCommentGroup&) { this->pushControl(); } |
| 165 void trackBounds(const AddComment&) { this->pushControl(); } |
| 166 void trackBounds(const EndCommentGroup&) { this->pushControl(); } |
| 167 void trackBounds(const DrawData&) { 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]); |
| 173 } |
| 174 |
| 175 void pushSaveBlock(const SkPaint* paint) { |
| 176 // Starting a new Save block. Push a new entry to represent that. |
| 177 SaveBounds sb = { 0, Bounds::MakeEmpty(), paint }; |
| 178 fSaveStack.push(sb); |
| 179 this->pushControl(); |
| 180 } |
| 181 |
| 182 static bool PaintMayAffectTransparentBlack(const SkPaint* paint) { |
| 183 if (paint) { |
| 184 // FIXME: this is very conservative |
| 185 if (paint->getImageFilter() || paint->getColorFilter()) { |
| 186 return true; |
| 187 } |
| 188 |
| 189 // Unusual Xfermodes require us to process a saved layer |
| 190 // even with operations outisde the clip. |
| 191 // For example, DstIn is used by masking layers. |
| 192 // https://code.google.com/p/skia/issues/detail?id=1291 |
| 193 // https://crbug.com/401593 |
| 194 SkXfermode* xfermode = paint->getXfermode(); |
| 195 SkXfermode::Mode mode; |
| 196 // SrcOver is ok, and is also the common case with a NULL xfermode. |
| 197 // So we should make that the fast path and bypass the mode extracti
on |
| 198 // and test. |
| 199 if (xfermode && xfermode->asMode(&mode)) { |
| 200 switch (mode) { |
| 201 // For each of the following transfer modes, if the source |
| 202 // alpha is zero (our transparent black), the resulting |
| 203 // blended alpha is not necessarily equal to the original |
| 204 // destination alpha. |
| 205 case SkXfermode::kClear_Mode: |
| 206 case SkXfermode::kSrc_Mode: |
| 207 case SkXfermode::kSrcIn_Mode: |
| 208 case SkXfermode::kDstIn_Mode: |
| 209 case SkXfermode::kSrcOut_Mode: |
| 210 case SkXfermode::kDstATop_Mode: |
| 211 case SkXfermode::kModulate_Mode: |
| 212 return true; |
| 213 break; |
| 214 default: |
| 215 break; |
| 216 } |
| 217 } |
| 218 } |
| 219 return false; |
| 220 } |
| 221 |
| 222 Bounds popSaveBlock() { |
| 223 // We're done the Save block. Apply the block's bounds to all control o
ps inside it. |
| 224 SaveBounds sb; |
| 225 fSaveStack.pop(&sb); |
| 226 |
| 227 // If the paint affects transparent black, we can't trust any of our cal
culated bounds. |
| 228 const Bounds& bounds = |
| 229 PaintMayAffectTransparentBlack(sb.paint) ? fCurrentClipBounds : sb.b
ounds; |
| 230 |
| 231 while (sb.controlOps-- > 0) { |
| 232 this->popControl(bounds); |
| 233 } |
| 234 |
| 235 // This whole Save block may be part another Save block. |
| 236 this->updateSaveBounds(bounds); |
| 237 |
| 238 // If called from a real Restore (not a phony one for balance), it'll ne
ed the bounds. |
| 239 return bounds; |
| 240 } |
| 241 |
| 242 void pushControl() { |
| 243 fControlIndices.push(fCurrentOp); |
| 244 if (!fSaveStack.isEmpty()) { |
| 245 fSaveStack.top().controlOps++; |
| 246 } |
| 247 } |
| 248 |
| 249 void popControl(const Bounds& bounds) { |
| 250 fBounds[fControlIndices.top()] = bounds; |
| 251 fControlIndices.pop(); |
| 252 } |
| 253 |
| 254 void updateSaveBounds(const Bounds& bounds) { |
| 255 // If we're in a Save block, expand its bounds to cover these bounds too
. |
| 256 if (!fSaveStack.isEmpty()) { |
| 257 fSaveStack.top().bounds.join(bounds); |
| 258 } |
| 259 } |
| 260 |
| 261 // FIXME: this method could use better bounds |
| 262 Bounds bounds(const DrawText&) const { return fCurrentClipBounds; } |
| 263 |
| 264 Bounds bounds(const Clear&) const { return kUnbounded; } // Igno
res the clip. |
| 265 Bounds bounds(const DrawPaint&) const { return fCurrentClipBounds; } |
| 266 Bounds bounds(const NoOp&) const { return Bounds::MakeEmpty(); } // NoOp
s don't draw. |
| 267 |
| 268 Bounds bounds(const DrawSprite& op) const { |
| 269 const SkBitmap& bm = op.bitmap; |
| 270 |
| 271 return Bounds::Make(SkIRect::MakeXYWH(op.left, op.top, bm.width(), bm.he
ight())); // Ignores the matrix. |
| 272 } |
| 273 |
| 274 Bounds bounds(const DrawRect& op) const { return this->adjustAndMap(op.rect,
&op.paint); } |
| 275 Bounds bounds(const DrawOval& op) const { return this->adjustAndMap(op.oval,
&op.paint); } |
| 276 Bounds bounds(const DrawRRect& op) const { |
| 277 return this->adjustAndMap(op.rrect.rect(), &op.paint); |
| 278 } |
| 279 Bounds bounds(const DrawDRRect& op) const { |
| 280 return this->adjustAndMap(op.outer.rect(), &op.paint); |
| 281 } |
| 282 Bounds bounds(const DrawImage& op) const { |
| 283 const SkImage* image = op.image; |
| 284 SkRect rect = SkRect::MakeXYWH(op.left, op.top, |
| 285 SkIntToScalar(image->width()), SkIntToSc
alar(image->height())); |
| 286 |
| 287 return this->adjustAndMap(rect, op.paint); |
| 288 } |
| 289 Bounds bounds(const DrawImageRect& op) const { |
| 290 return this->adjustAndMap(op.dst, op.paint); |
| 291 } |
| 292 Bounds bounds(const DrawBitmapRectToRect& op) const { |
| 293 return this->adjustAndMap(op.dst, op.paint); |
| 294 } |
| 295 Bounds bounds(const DrawBitmapNine& op) const { |
| 296 return this->adjustAndMap(op.dst, op.paint); |
| 297 } |
| 298 Bounds bounds(const DrawBitmap& op) const { |
| 299 const SkBitmap& bm = op.bitmap; |
| 300 return this->adjustAndMap(SkRect::MakeXYWH(op.left, op.top, SkIntToScala
r(bm.width()), SkIntToScalar(bm.height())), |
| 301 op.paint); |
| 302 } |
| 303 Bounds bounds(const DrawBitmapMatrix& op) const { |
| 304 const SkBitmap& bm = op.bitmap; |
| 305 SkRect dst = SkRect::Make(SkIRect::MakeWH(bm.width(), bm.height())); |
| 306 op.matrix.mapRect(&dst); |
| 307 return this->adjustAndMap(dst, op.paint); |
| 308 } |
| 309 |
| 310 Bounds bounds(const DrawPath& op) const { |
| 311 return op.path.isInverseFillType() ? fCurrentClipBounds |
| 312 : this->adjustAndMap(op.path.getBounds(), &op.paint); |
| 313 } |
| 314 Bounds bounds(const DrawPoints& op) const { |
| 315 SkRect dst; |
| 316 dst.set(op.pts, op.count); |
| 317 |
| 318 // Pad the bounding box a little to make sure hairline points' bounds ar
en't empty. |
| 319 SkScalar stroke = SkMaxScalar(op.paint.getStrokeWidth(), 0.01f); |
| 320 dst.outset(stroke / 2, stroke / 2); |
| 321 |
| 322 return this->adjustAndMap(dst, &op.paint); |
| 323 } |
| 324 Bounds bounds(const DrawPatch& op) const { |
| 325 SkRect dst; |
| 326 dst.set(op.cubics, SkPatchUtils::kNumCtrlPts); |
| 327 return this->adjustAndMap(dst, &op.paint); |
| 328 } |
| 329 Bounds bounds(const DrawVertices& op) const { |
| 330 SkRect dst; |
| 331 dst.set(op.vertices, op.vertexCount); |
| 332 return this->adjustAndMap(dst, &op.paint); |
| 333 } |
| 334 |
| 335 Bounds bounds(const DrawPicture& op) const { |
| 336 SkRect dst = op.picture->cullRect(); |
| 337 if (op.matrix) { |
| 338 op.matrix->mapRect(&dst); |
| 339 } |
| 340 return this->adjustAndMap(dst, op.paint); |
| 341 } |
| 342 |
| 343 Bounds bounds(const DrawPosText& op) const { |
| 344 const int N = op.paint.countText(op.text, op.byteLength); |
| 345 if (N == 0) { |
| 346 return Bounds::MakeEmpty(); |
| 347 } |
| 348 |
| 349 SkRect dst; |
| 350 dst.set(op.pos, N); |
| 351 AdjustTextForFontMetrics(&dst, op.paint); |
| 352 return this->adjustAndMap(dst, &op.paint); |
| 353 } |
| 354 Bounds bounds(const DrawPosTextH& op) const { |
| 355 const int N = op.paint.countText(op.text, op.byteLength); |
| 356 if (N == 0) { |
| 357 return Bounds::MakeEmpty(); |
| 358 } |
| 359 |
| 360 SkScalar left = op.xpos[0], right = op.xpos[0]; |
| 361 for (int i = 1; i < N; i++) { |
| 362 left = SkMinScalar(left, op.xpos[i]); |
| 363 right = SkMaxScalar(right, op.xpos[i]); |
| 364 } |
| 365 SkRect dst = { left, op.y, right, op.y }; |
| 366 AdjustTextForFontMetrics(&dst, op.paint); |
| 367 return this->adjustAndMap(dst, &op.paint); |
| 368 } |
| 369 Bounds bounds(const DrawTextOnPath& op) const { |
| 370 SkRect dst = op.path.getBounds(); |
| 371 |
| 372 // Pad all sides by the maximum padding in any direction we'd normally a
pply. |
| 373 SkRect pad = { 0, 0, 0, 0 }; |
| 374 AdjustTextForFontMetrics(&pad, op.paint); |
| 375 |
| 376 // That maximum padding happens to always be the right pad today. |
| 377 SkASSERT(pad.fLeft == -pad.fRight); |
| 378 SkASSERT(pad.fTop == -pad.fBottom); |
| 379 SkASSERT(pad.fRight > pad.fBottom); |
| 380 dst.outset(pad.fRight, pad.fRight); |
| 381 |
| 382 return this->adjustAndMap(dst, &op.paint); |
| 383 } |
| 384 |
| 385 Bounds bounds(const DrawTextBlob& op) const { |
| 386 SkRect dst = op.blob->bounds(); |
| 387 dst.offset(op.x, op.y); |
| 388 return this->adjustAndMap(dst, &op.paint); |
| 389 } |
| 390 |
| 391 static void AdjustTextForFontMetrics(SkRect* rect, const SkPaint& paint) { |
| 392 #ifdef SK_DEBUG |
| 393 SkRect correct = *rect; |
| 394 #endif |
| 395 // crbug.com/373785 ~~> xPad = 4x yPad |
| 396 // crbug.com/424824 ~~> bump yPad from 2x text size to 2.5x |
| 397 const SkScalar yPad = 2.5f * paint.getTextSize(), |
| 398 xPad = 4.0f * yPad; |
| 399 rect->outset(xPad, yPad); |
| 400 #ifdef SK_DEBUG |
| 401 SkPaint::FontMetrics metrics; |
| 402 paint.getFontMetrics(&metrics); |
| 403 correct.fLeft += metrics.fXMin; |
| 404 correct.fTop += metrics.fTop; |
| 405 correct.fRight += metrics.fXMax; |
| 406 correct.fBottom += metrics.fBottom; |
| 407 // See skia:2862 for why we ignore small text sizes. |
| 408 SkASSERTF(paint.getTextSize() < 0.001f || rect->contains(correct), |
| 409 "%f %f %f %f vs. %f %f %f %f\n", |
| 410 -xPad, -yPad, +xPad, +yPad, |
| 411 metrics.fXMin, metrics.fTop, metrics.fXMax, metrics.fBottom)
; |
| 412 #endif |
| 413 } |
| 414 |
| 415 //--------- LAYER HOISTING |
| 416 template <typename T> void trackSaveLayers(const T& op) { |
| 417 /* most ops aren't involved in saveLayers */ |
| 418 } |
| 419 void trackSaveLayers(const Save& s) { this->pushSaveLayerInfo(false, NULL);
} |
| 420 void trackSaveLayers(const SaveLayer& sl) { |
| 421 this->pushSaveLayerInfo(true, sl.paint); |
| 422 } |
| 423 void trackSaveLayers(const Restore& r) { this->popSaveLayerInfo(); } |
| 424 void trackSaveLayers(const DrawPicture& dp) { |
104 // For sub-pictures, we wrap their layer information within the parent | 425 // For sub-pictures, we wrap their layer information within the parent |
105 // picture's rendering hierarchy | 426 // picture's rendering hierarchy |
106 const GrAccelData* childData = GPUOptimize(dp.picture); | 427 const GrAccelData* childData = GPUOptimize(dp.picture); |
107 | 428 |
108 for (int i = 0; i < childData->numSaveLayers(); ++i) { | 429 for (int i = 0; i < childData->numSaveLayers(); ++i) { |
109 const GrAccelData::SaveLayerInfo& src = childData->saveLayerInfo(i); | 430 const GrAccelData::SaveLayerInfo& src = childData->saveLayerInfo(i); |
110 | 431 |
111 SkRect srcRect = SkRect::Make(src.fBounds); | 432 Bounds newClip(fCurrentClipBounds); |
112 SkIRect newClip(fCurrentClipBounds); | |
113 | 433 |
114 if (!newClip.intersect(this->adjustAndMap(srcRect, dp.paint))) { | 434 if (!newClip.intersect(this->adjustAndMap(src.fBounds, dp.paint))) { |
115 continue; | 435 continue; |
116 } | 436 } |
117 | 437 |
118 this->updateStackForSaveLayer(); | 438 this->updateStackForSaveLayer(); |
119 | 439 |
120 GrAccelData::SaveLayerInfo& dst = fAccelData->addSaveLayerInfo(); | 440 GrAccelData::SaveLayerInfo& dst = fAccelData->addSaveLayerInfo(); |
121 | 441 |
122 // If src.fPicture is NULL the layer is in dp.picture; otherwise | 442 // If src.fPicture is NULL the layer is in dp.picture; otherwise |
123 // it belongs to a sub-picture. | 443 // it belongs to a sub-picture. |
124 dst.fPicture = src.fPicture ? src.fPicture : static_cast<const SkPic
ture*>(dp.picture); | 444 dst.fPicture = src.fPicture ? src.fPicture : static_cast<const SkPic
ture*>(dp.picture); |
125 dst.fPicture->ref(); | 445 dst.fPicture->ref(); |
126 dst.fBounds = newClip; | 446 dst.fBounds = newClip; |
127 dst.fLocalMat = src.fLocalMat; | 447 dst.fLocalMat = src.fLocalMat; |
128 dst.fPreMat = src.fPreMat; | 448 dst.fPreMat = src.fPreMat; |
129 dst.fPreMat.postConcat(*fCTM); | 449 dst.fPreMat.postConcat(*fCTM); |
130 if (src.fPaint) { | 450 if (src.fPaint) { |
131 dst.fPaint = SkNEW_ARGS(SkPaint, (*src.fPaint)); | 451 dst.fPaint = SkNEW_ARGS(SkPaint, (*src.fPaint)); |
132 } | 452 } |
133 dst.fSaveLayerOpID = src.fSaveLayerOpID; | 453 dst.fSaveLayerOpID = src.fSaveLayerOpID; |
134 dst.fRestoreOpID = src.fRestoreOpID; | 454 dst.fRestoreOpID = src.fRestoreOpID; |
135 dst.fHasNestedLayers = src.fHasNestedLayers; | 455 dst.fHasNestedLayers = src.fHasNestedLayers; |
136 dst.fIsNested = fSaveLayersInStack > 0 || src.fIsNested; | 456 dst.fIsNested = fSaveLayersInStack > 0 || src.fIsNested; |
137 } | 457 } |
138 } | 458 } |
139 | 459 |
140 void pushSaveBlock() { | |
141 fSaveStack.push(SaveInfo(fCurrentOp, false, NULL, SkIRect::MakeEmpty()))
; | |
142 } | |
143 | |
144 // Inform all the saveLayers already on the stack that they now have a | 460 // Inform all the saveLayers already on the stack that they now have a |
145 // nested saveLayer inside them | 461 // nested saveLayer inside them |
146 void updateStackForSaveLayer() { | 462 void updateStackForSaveLayer() { |
147 for (int index = fSaveStack.count() - 1; index >= 0; --index) { | 463 for (int index = fSaveLayerStack.count() - 1; index >= 0; --index) { |
148 if (fSaveStack[index].fHasNestedSaveLayer) { | 464 if (fSaveLayerStack[index].fHasNestedSaveLayer) { |
149 break; | 465 break; |
150 } | 466 } |
151 fSaveStack[index].fHasNestedSaveLayer = true; | 467 fSaveLayerStack[index].fHasNestedSaveLayer = true; |
152 if (fSaveStack[index].fIsSaveLayer) { | 468 if (fSaveLayerStack[index].fIsSaveLayer) { |
153 break; | 469 break; |
154 } | 470 } |
155 } | 471 } |
156 } | 472 } |
157 | 473 |
158 void pushSaveLayerBlock(const SkPaint* paint) { | 474 void pushSaveLayerInfo(bool isSaveLayer, const SkPaint* paint) { |
159 this->updateStackForSaveLayer(); | 475 if (isSaveLayer) { |
| 476 this->updateStackForSaveLayer(); |
| 477 ++fSaveLayersInStack; |
| 478 } |
160 | 479 |
161 fSaveStack.push(SaveInfo(fCurrentOp, true, paint, fCurrentClipBounds)); | 480 fSaveLayerStack.push(SaveLayerInfo(fCurrentOp, isSaveLayer, paint, fCurr
entClipBounds)); |
162 ++fSaveLayersInStack; | |
163 } | 481 } |
164 | 482 |
165 void popSaveBlock() { | 483 void popSaveLayerInfo() { |
166 if (fSaveStack.count() <= 0) { | 484 if (fSaveLayerStack.count() <= 0) { |
167 SkASSERT(false); | 485 SkASSERT(false); |
168 return; | 486 return; |
169 } | 487 } |
170 | 488 |
171 SaveInfo si; | 489 SaveLayerInfo sli; |
172 fSaveStack.pop(&si); | 490 fSaveLayerStack.pop(&sli); |
173 | 491 |
174 if (!si.fIsSaveLayer) { | 492 if (!sli.fIsSaveLayer) { |
175 return; | 493 return; |
176 } | 494 } |
177 | 495 |
178 --fSaveLayersInStack; | 496 --fSaveLayersInStack; |
179 | 497 |
180 GrAccelData::SaveLayerInfo& slInfo = fAccelData->addSaveLayerInfo(); | 498 GrAccelData::SaveLayerInfo& slInfo = fAccelData->addSaveLayerInfo(); |
181 | 499 |
182 SkASSERT(NULL == slInfo.fPicture); // This layer is in the top-most pic
ture | 500 SkASSERT(NULL == slInfo.fPicture); // This layer is in the top-most pic
ture |
183 slInfo.fBounds = si.fBounds; | 501 |
| 502 slInfo.fBounds = fBounds[sli.fStartIndex]; |
| 503 slInfo.fBounds.intersect(sli.fClipBound); |
184 slInfo.fLocalMat = *fCTM; | 504 slInfo.fLocalMat = *fCTM; |
185 slInfo.fPreMat = SkMatrix::I(); | 505 slInfo.fPreMat = SkMatrix::I(); |
186 if (si.fPaint) { | 506 if (sli.fPaint) { |
187 slInfo.fPaint = SkNEW_ARGS(SkPaint, (*si.fPaint)); | 507 slInfo.fPaint = SkNEW_ARGS(SkPaint, (*sli.fPaint)); |
188 } | 508 } |
189 slInfo.fSaveLayerOpID = si.fStartIndex; | 509 slInfo.fSaveLayerOpID = sli.fStartIndex; |
190 slInfo.fRestoreOpID = fCurrentOp; | 510 slInfo.fRestoreOpID = fCurrentOp; |
191 slInfo.fHasNestedLayers = si.fHasNestedSaveLayer; | 511 slInfo.fHasNestedLayers = sli.fHasNestedSaveLayer; |
192 slInfo.fIsNested = fSaveLayersInStack > 0; | 512 slInfo.fIsNested = fSaveLayersInStack > 0; |
193 } | 513 } |
| 514 //--------- LAYER HOISTING |
194 | 515 |
195 // Returns true if rect was meaningfully adjusted for the effects of paint, | 516 // Returns true if rect was meaningfully adjusted for the effects of paint, |
196 // false if the paint could affect the rect in unknown ways. | 517 // false if the paint could affect the rect in unknown ways. |
197 static bool AdjustForPaint(const SkPaint* paint, SkRect* rect) { | 518 static bool AdjustForPaint(const SkPaint* paint, SkRect* rect) { |
198 if (paint) { | 519 if (paint) { |
199 if (paint->canComputeFastBounds()) { | 520 if (paint->canComputeFastBounds()) { |
200 *rect = paint->computeFastBounds(*rect, rect); | 521 *rect = paint->computeFastBounds(*rect, rect); |
201 return true; | 522 return true; |
202 } | 523 } |
203 return false; | 524 return false; |
204 } | 525 } |
205 return true; | 526 return true; |
206 } | 527 } |
207 | 528 |
208 // Adjust rect for all paints that may affect its geometry, then map it to d
evice space. | 529 bool adjustForSaveLayerPaints(SkRect* rect, int savesToIgnore = 0) const { |
209 SkIRect adjustAndMap(SkRect rect, const SkPaint* paint) const { | 530 for (int i = fSaveStack.count() - 1 - savesToIgnore; i >= 0; i--) { |
| 531 if (!AdjustForPaint(fSaveStack[i].paint, rect)) { |
| 532 return false; |
| 533 } |
| 534 } |
| 535 return true; |
| 536 } |
| 537 |
| 538 // Adjust rect for all paints that may affect its geometry, then map it to i
dentity space. |
| 539 Bounds adjustAndMap(SkRect rect, const SkPaint* paint) const { |
210 // Inverted rectangles really confuse our BBHs. | 540 // Inverted rectangles really confuse our BBHs. |
211 rect.sort(); | 541 rect.sort(); |
212 | 542 |
213 // Adjust the rect for its own paint. | 543 // Adjust the rect for its own paint. |
214 if (!AdjustForPaint(paint, &rect)) { | 544 if (!AdjustForPaint(paint, &rect)) { |
215 // The paint could do anything to our bounds. The only safe answer
is the current clip. | 545 // The paint could do anything to our bounds. The only safe answer
is the current clip. |
216 return fCurrentClipBounds; | 546 return fCurrentClipBounds; |
217 } | 547 } |
218 | 548 |
219 // Adjust rect for all the paints from the SaveLayers we're inside. | 549 // Adjust rect for all the paints from the SaveLayers we're inside. |
220 for (int i = fSaveStack.count() - 1; i >= 0; i--) { | 550 if (!this->adjustForSaveLayerPaints(&rect)) { |
221 if (!AdjustForPaint(fSaveStack[i].fPaint, &rect)) { | 551 // Same deal as above. |
222 // Same deal as above. | 552 return fCurrentClipBounds; |
223 return fCurrentClipBounds; | |
224 } | |
225 } | 553 } |
226 | 554 |
227 // Map the rect back to device space. | 555 // Map the rect back to identity space. |
228 fCTM->mapRect(&rect); | 556 fCTM->mapRect(&rect); |
229 SkIRect devRect; | |
230 rect.roundOut(&devRect); | |
231 | 557 |
232 // Nothing can draw outside the current clip. | 558 // Nothing can draw outside the current clip. |
233 // (Only bounded ops call into this method, so oddballs like Clear don't
matter here.) | 559 // (Only bounded ops call into this method, so oddballs like Clear don't
matter here.) |
234 devRect.intersect(fCurrentClipBounds); | 560 rect.intersect(fCurrentClipBounds); |
235 return devRect; | 561 return rect; |
236 } | 562 } |
| 563 |
| 564 // Conservative identity-space bounds for each op in the SkRecord. |
| 565 SkAutoTMalloc<Bounds> fBounds; |
| 566 |
| 567 // We walk fCurrentOp through the SkRecord, as we go using updateCTM() |
| 568 // and updateClipBounds() to maintain the exact CTM (fCTM) and conservative |
| 569 // identity-space bounds of the current clip (fCurrentClipBounds). |
| 570 unsigned fCurrentOp; |
| 571 const SkMatrix* fCTM; |
| 572 Bounds fCurrentClipBounds; |
| 573 |
| 574 // Used to track the bounds of Save/Restore blocks and the control ops insid
e them. |
| 575 SkTDArray<SaveBounds> fSaveStack; |
| 576 SkTDArray<unsigned> fControlIndices; |
| 577 |
| 578 //--------- LAYER HOISTING |
| 579 // Used to collect saveLayer information for layer hoisting |
| 580 uint32_t fPictureID; |
| 581 int fSaveLayersInStack; |
| 582 SkTDArray<SaveLayerInfo> fSaveLayerStack; |
| 583 GrAccelData* fAccelData; |
| 584 //--------- LAYER HOISTING |
237 }; | 585 }; |
238 | 586 |
| 587 } // namespace SkRecords |
239 | 588 |
240 // GPUOptimize is only intended to be called within the context of SkGpuDevice's | 589 // GPUOptimize is only intended to be called within the context of SkGpuDevice's |
241 // EXPERIMENTAL_optimize method. | 590 // EXPERIMENTAL_optimize method. |
242 const GrAccelData* GPUOptimize(const SkPicture* pict) { | 591 const GrAccelData* GPUOptimize(const SkPicture* pict) { |
243 if (NULL == pict || pict->cullRect().isEmpty()) { | 592 if (NULL == pict || pict->cullRect().isEmpty()) { |
244 return NULL; | 593 return NULL; |
245 } | 594 } |
246 | 595 |
247 SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey(); | 596 SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey(); |
248 | 597 |
249 const GrAccelData* existing = | 598 const GrAccelData* existing = |
250 static_cast<const GrAccelData*>(pict->EXPERIMENTAL_g
etAccelData(key)); | 599 static_cast<const GrAccelData*>(pict->EXPERIMENTAL_g
etAccelData(key)); |
251 if (existing) { | 600 if (existing) { |
252 return existing; | 601 return existing; |
253 } | 602 } |
254 | 603 |
255 SkAutoTUnref<GrAccelData> data(SkNEW_ARGS(GrAccelData, (key))); | 604 SkAutoTUnref<GrAccelData> data(SkNEW_ARGS(GrAccelData, (key))); |
256 | 605 |
257 pict->EXPERIMENTAL_addAccelData(data); | 606 pict->EXPERIMENTAL_addAccelData(data); |
258 | 607 |
259 CollectLayers collector(pict, data); | 608 SkRecords::CollectLayers collector(pict, data); |
260 | 609 |
261 return data; | 610 return data; |
262 } | 611 } |
OLD | NEW |