| 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 |