| 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 "SkCanvas.h" | 8 #include "SkCanvas.h" |
| 9 #include "SkPictureData.h" | 9 #include "SkPictureData.h" |
| 10 #include "SkPicturePlayback.h" | 10 #include "SkPicturePlayback.h" |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 99 void get_text(SkReader32* reader, TextContainer* text) { | 99 void get_text(SkReader32* reader, TextContainer* text) { |
| 100 size_t length = text->fByteLength = reader->readInt(); | 100 size_t length = text->fByteLength = reader->readInt(); |
| 101 text->fText = (const char*)reader->skip(length); | 101 text->fText = (const char*)reader->skip(length); |
| 102 } | 102 } |
| 103 | 103 |
| 104 // FIXME: SkBitmaps are stateful, so we need to copy them to play back in multip
le threads. | 104 // FIXME: SkBitmaps are stateful, so we need to copy them to play back in multip
le threads. |
| 105 static SkBitmap shallow_copy(const SkBitmap& bitmap) { | 105 static SkBitmap shallow_copy(const SkBitmap& bitmap) { |
| 106 return bitmap; | 106 return bitmap; |
| 107 } | 107 } |
| 108 | 108 |
| 109 void SkPicturePlayback::draw(SkCanvas* canvas, SkDrawPictureCallback* callback)
{ | 109 const SkPicture::OperationList* SkPicturePlayback::getActiveOps(const SkCanvas*
canvas) { |
| 110 AutoResetOpID aroi(this); | |
| 111 SkASSERT(0 == fCurOffset); | |
| 112 | |
| 113 // kDrawComplete will be the signal that we have reached the end of | |
| 114 // the command stream | |
| 115 static const uint32_t kDrawComplete = SK_MaxU32; | |
| 116 | |
| 117 SkReader32 reader(fPictureData->fOpData->bytes(), fPictureData->fOpData->siz
e()); | |
| 118 SkAutoTDelete<const SkPicture::OperationList> activeOpsList; | |
| 119 const SkTDArray<void*>* activeOps = NULL; | |
| 120 | 110 |
| 121 if (fUseBBH && NULL != fPictureData->fStateTree && NULL != fPictureData->fBo
undingHierarchy) { | 111 if (fUseBBH && NULL != fPictureData->fStateTree && NULL != fPictureData->fBo
undingHierarchy) { |
| 122 SkRect clipBounds; | 112 SkRect clipBounds; |
| 123 if (canvas->getClipBounds(&clipBounds)) { | 113 if (canvas->getClipBounds(&clipBounds)) { |
| 124 SkIRect query; | 114 SkIRect query; |
| 125 clipBounds.roundOut(&query); | 115 clipBounds.roundOut(&query); |
| 126 | 116 |
| 127 activeOpsList.reset(fPictureData->getActiveOps(query)); | 117 return fPictureData->getActiveOps(query); |
| 128 if (NULL != activeOpsList.get()) { | 118 } |
| 129 if (0 == activeOpsList->numOps()) { | 119 } |
| 130 return; // nothing to draw | 120 |
| 121 return NULL; |
| 122 } |
| 123 |
| 124 // Initialize the state tree iterator. Return false if there is nothing left to
draw. |
| 125 bool SkPicturePlayback::initIterator(SkPictureStateTree::Iterator* iter, |
| 126 SkCanvas* canvas, |
| 127 const SkPicture::OperationList *activeOpsLi
st) { |
| 128 |
| 129 if (NULL != activeOpsList) { |
| 130 if (0 == activeOpsList->numOps()) { |
| 131 return false; // nothing to draw |
| 132 } |
| 133 |
| 134 fPictureData->fStateTree->initIterator(iter, activeOpsList->fOps, canvas
); |
| 135 } |
| 136 |
| 137 return true; |
| 138 } |
| 139 |
| 140 bool SkPicturePlayback::replaceOps(SkPictureStateTree::Iterator* iter, |
| 141 SkReader32* reader, |
| 142 SkCanvas* canvas, |
| 143 const SkMatrix& initialMatrix) { |
| 144 if (NULL != fReplacements) { |
| 145 // Potentially replace a block of operations with a single drawBitmap ca
ll |
| 146 SkPicturePlayback::PlaybackReplacements::ReplacementInfo* temp = |
| 147 fReplacements->lookupByStart(reader-
>offset()); |
| 148 if (NULL != temp) { |
| 149 SkASSERT(NULL != temp->fBM); |
| 150 SkASSERT(NULL != temp->fPaint); |
| 151 canvas->save(); |
| 152 canvas->setMatrix(initialMatrix); |
| 153 SkRect src = SkRect::Make(temp->fSrcRect); |
| 154 SkRect dst = SkRect::MakeXYWH(temp->fPos.fX, temp->fPos.fY, |
| 155 temp->fSrcRect.width(), |
| 156 temp->fSrcRect.height()); |
| 157 canvas->drawBitmapRectToRect(*temp->fBM, &src, dst, temp->fPaint); |
| 158 canvas->restore(); |
| 159 |
| 160 if (iter->isValid()) { |
| 161 // This save is needed since the BBH will automatically issue |
| 162 // a restore to balanced the saveLayer we're skipping |
| 163 canvas->save(); |
| 164 |
| 165 // At this point we know that the PictureStateTree was aiming |
| 166 // for some draw op within temp's saveLayer (although potentiall
y |
| 167 // in a separate saveLayer nested inside it). |
| 168 // We need to skip all the operations inside temp's range |
| 169 // along with all the associated state changes but update |
| 170 // the state tree to the first operation outside temp's range. |
| 171 |
| 172 uint32_t skipTo; |
| 173 do { |
| 174 skipTo = iter->nextDraw(); |
| 175 if (SkPictureStateTree::Iterator::kDrawComplete == skipTo) { |
| 176 break; |
| 177 } |
| 178 |
| 179 if (skipTo <= temp->fStop) { |
| 180 reader->setOffset(skipTo); |
| 181 uint32_t size; |
| 182 DrawType op = ReadOpAndSize(reader, &size); |
| 183 // Since we are relying on the normal SkPictureStateTree |
| 184 // playback we need to convert any nested saveLayer call
s |
| 185 // it may issue into saves (so that all its internal |
| 186 // restores will be balanced). |
| 187 if (SAVE_LAYER == op) { |
| 188 canvas->save(); |
| 189 } |
| 190 } |
| 191 } while (skipTo <= temp->fStop); |
| 192 |
| 193 if (SkPictureStateTree::Iterator::kDrawComplete == skipTo) { |
| 194 reader->setOffset(reader->size()); // skip to end |
| 195 return true; |
| 131 } | 196 } |
| 132 | 197 |
| 133 activeOps = &(activeOpsList.get()->fOps); | 198 reader->setOffset(skipTo); |
| 199 } else { |
| 200 reader->setOffset(temp->fStop); |
| 201 uint32_t size; |
| 202 SkDEBUGCODE(DrawType op = ) ReadOpAndSize(reader, &size); |
| 203 SkASSERT(RESTORE == op); |
| 134 } | 204 } |
| 205 |
| 206 return true; |
| 135 } | 207 } |
| 136 } | 208 } |
| 137 | 209 |
| 138 SkPictureStateTree::Iterator it = (NULL == activeOps) ? | 210 return false; |
| 139 SkPictureStateTree::Iterator() : | 211 } |
| 140 fPictureData->fStateTree->getIterator(*activeOps, canvas); | |
| 141 | 212 |
| 142 if (it.isValid()) { | 213 // If 'iter' is valid use it to skip forward through the picture. |
| 143 uint32_t skipTo = it.nextDraw(); | 214 void SkPicturePlayback::StepIterator(SkPictureStateTree::Iterator* iter, SkReade
r32* reader) { |
| 144 if (kDrawComplete == skipTo) { | 215 if (iter->isValid()) { |
| 145 return; | 216 uint32_t skipTo = iter->nextDraw(); |
| 217 if (SkPictureStateTree::Iterator::kDrawComplete == skipTo) { |
| 218 reader->setOffset(reader->size()); // skip to end |
| 219 } else { |
| 220 reader->setOffset(skipTo); |
| 146 } | 221 } |
| 147 reader.setOffset(skipTo); | |
| 148 } | 222 } |
| 223 } |
| 224 |
| 225 // Update the iterator and state tree to catch up with the skipped ops. |
| 226 void SkPicturePlayback::SkipIterTo(SkPictureStateTree::Iterator* iter, |
| 227 SkReader32* reader, |
| 228 uint32_t skipTo) { |
| 229 SkASSERT(skipTo <= reader->size()); |
| 230 SkASSERT(reader->offset() <= skipTo); // should only be skipping forward |
| 231 |
| 232 if (iter->isValid()) { |
| 233 // If using a bounding box hierarchy, advance the state tree |
| 234 // iterator until at or after skipTo |
| 235 uint32_t adjustedSkipTo; |
| 236 do { |
| 237 adjustedSkipTo = iter->nextDraw(); |
| 238 } while (adjustedSkipTo < skipTo); |
| 239 skipTo = adjustedSkipTo; |
| 240 } |
| 241 if (SkPictureStateTree::Iterator::kDrawComplete == skipTo) { |
| 242 reader->setOffset(reader->size()); // skip to end |
| 243 } else { |
| 244 reader->setOffset(skipTo); |
| 245 } |
| 246 } |
| 247 |
| 248 void SkPicturePlayback::draw(SkCanvas* canvas, SkDrawPictureCallback* callback)
{ |
| 249 AutoResetOpID aroi(this); |
| 250 SkASSERT(0 == fCurOffset); |
| 251 |
| 252 SkAutoTDelete<const SkPicture::OperationList> activeOpsList(this->getActiveO
ps(canvas)); |
| 253 SkPictureStateTree::Iterator it; |
| 254 |
| 255 if (!this->initIterator(&it, canvas, activeOpsList.get())) { |
| 256 return; // nothing to draw |
| 257 } |
| 258 |
| 259 SkReader32 reader(fPictureData->opData()->bytes(), fPictureData->opData()->s
ize()); |
| 260 |
| 261 StepIterator(&it, &reader); |
| 149 | 262 |
| 150 // Record this, so we can concat w/ it if we encounter a setMatrix() | 263 // Record this, so we can concat w/ it if we encounter a setMatrix() |
| 151 SkMatrix initialMatrix = canvas->getTotalMatrix(); | 264 SkMatrix initialMatrix = canvas->getTotalMatrix(); |
| 152 | 265 |
| 153 SkAutoCanvasRestore acr(canvas, false); | 266 SkAutoCanvasRestore acr(canvas, false); |
| 154 | 267 |
| 155 while (!reader.eof()) { | 268 while (!reader.eof()) { |
| 156 if (callback && callback->abortDrawing()) { | 269 if (NULL != callback && callback->abortDrawing()) { |
| 157 return; | 270 return; |
| 158 } | 271 } |
| 159 | 272 |
| 160 if (NULL != fReplacements) { | 273 if (this->replaceOps(&it, &reader, canvas, initialMatrix)) { |
| 161 // Potentially replace a block of operations with a single drawBitma
p call | 274 continue; |
| 162 SkPicturePlayback::PlaybackReplacements::ReplacementInfo* temp = | |
| 163 fReplacements->lookupByStart(reader.offset()); | |
| 164 if (NULL != temp) { | |
| 165 SkASSERT(NULL != temp->fBM); | |
| 166 SkASSERT(NULL != temp->fPaint); | |
| 167 canvas->save(); | |
| 168 canvas->setMatrix(initialMatrix); | |
| 169 SkRect src = SkRect::Make(temp->fSrcRect); | |
| 170 SkRect dst = SkRect::MakeXYWH(temp->fPos.fX, temp->fPos.fY, | |
| 171 temp->fSrcRect.width(), | |
| 172 temp->fSrcRect.height()); | |
| 173 canvas->drawBitmapRectToRect(*temp->fBM, &src, dst, temp->fPaint
); | |
| 174 canvas->restore(); | |
| 175 | |
| 176 if (it.isValid()) { | |
| 177 // This save is needed since the BBH will automatically issu
e | |
| 178 // a restore to balanced the saveLayer we're skipping | |
| 179 canvas->save(); | |
| 180 | |
| 181 // At this point we know that the PictureStateTree was aimin
g | |
| 182 // for some draw op within temp's saveLayer (although potent
ially | |
| 183 // in a separate saveLayer nested inside it). | |
| 184 // We need to skip all the operations inside temp's range | |
| 185 // along with all the associated state changes but update | |
| 186 // the state tree to the first operation outside temp's rang
e. | |
| 187 | |
| 188 uint32_t skipTo; | |
| 189 do { | |
| 190 skipTo = it.nextDraw(); | |
| 191 if (kDrawComplete == skipTo) { | |
| 192 break; | |
| 193 } | |
| 194 | |
| 195 if (skipTo <= temp->fStop) { | |
| 196 reader.setOffset(skipTo); | |
| 197 uint32_t size; | |
| 198 DrawType op = ReadOpAndSize(&reader, &size); | |
| 199 // Since we are relying on the normal SkPictureState
Tree | |
| 200 // playback we need to convert any nested saveLayer
calls | |
| 201 // it may issue into saves (so that all its internal | |
| 202 // restores will be balanced). | |
| 203 if (SAVE_LAYER == op) { | |
| 204 canvas->save(); | |
| 205 } | |
| 206 } | |
| 207 } while (skipTo <= temp->fStop); | |
| 208 | |
| 209 if (kDrawComplete == skipTo) { | |
| 210 break; | |
| 211 } | |
| 212 | |
| 213 reader.setOffset(skipTo); | |
| 214 } else { | |
| 215 reader.setOffset(temp->fStop); | |
| 216 uint32_t size; | |
| 217 SkDEBUGCODE(DrawType op = ) ReadOpAndSize(&reader, &size); | |
| 218 SkASSERT(RESTORE == op); | |
| 219 } | |
| 220 continue; | |
| 221 } | |
| 222 } | 275 } |
| 223 | 276 |
| 224 fCurOffset = reader.offset(); | 277 fCurOffset = reader.offset(); |
| 225 uint32_t size; | 278 uint32_t size; |
| 226 DrawType op = ReadOpAndSize(&reader, &size); | 279 DrawType op = ReadOpAndSize(&reader, &size); |
| 227 size_t skipTo = 0; | |
| 228 if (NOOP == op) { | 280 if (NOOP == op) { |
| 229 // NOOPs are to be ignored - do not propagate them any further | 281 // NOOPs are to be ignored - do not propagate them any further |
| 230 skipTo = fCurOffset + size; | 282 SkipIterTo(&it, &reader, fCurOffset + size); |
| 231 } | |
| 232 | |
| 233 if (0 != skipTo) { | |
| 234 if (it.isValid()) { | |
| 235 // If using a bounding box hierarchy, advance the state tree | |
| 236 // iterator until at or after skipTo | |
| 237 uint32_t adjustedSkipTo; | |
| 238 do { | |
| 239 adjustedSkipTo = it.nextDraw(); | |
| 240 } while (adjustedSkipTo < skipTo); | |
| 241 skipTo = adjustedSkipTo; | |
| 242 } | |
| 243 if (kDrawComplete == skipTo) { | |
| 244 break; | |
| 245 } | |
| 246 reader.setOffset(skipTo); | |
| 247 continue; | 283 continue; |
| 248 } | 284 } |
| 249 | 285 |
| 250 this->handleOp(&reader, op, size, canvas, initialMatrix); | 286 this->handleOp(&reader, op, size, canvas, initialMatrix); |
| 251 | 287 |
| 252 if (it.isValid()) { | 288 StepIterator(&it, &reader); |
| 253 uint32_t skipTo = it.nextDraw(); | |
| 254 if (kDrawComplete == skipTo) { | |
| 255 break; | |
| 256 } | |
| 257 reader.setOffset(skipTo); | |
| 258 } | |
| 259 } | 289 } |
| 260 } | 290 } |
| 261 | 291 |
| 262 void SkPicturePlayback::handleOp(SkReader32* reader, | 292 void SkPicturePlayback::handleOp(SkReader32* reader, |
| 263 DrawType op, | 293 DrawType op, |
| 264 uint32_t size, | 294 uint32_t size, |
| 265 SkCanvas* canvas, | 295 SkCanvas* canvas, |
| 266 const SkMatrix& initialMatrix) { | 296 const SkMatrix& initialMatrix) { |
| 267 switch (op) { | 297 switch (op) { |
| 268 case CLIP_PATH: { | 298 case CLIP_PATH: { |
| (...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 566 case TRANSLATE: { | 596 case TRANSLATE: { |
| 567 SkScalar dx = reader->readScalar(); | 597 SkScalar dx = reader->readScalar(); |
| 568 SkScalar dy = reader->readScalar(); | 598 SkScalar dy = reader->readScalar(); |
| 569 canvas->translate(dx, dy); | 599 canvas->translate(dx, dy); |
| 570 } break; | 600 } break; |
| 571 default: | 601 default: |
| 572 SkASSERT(0); | 602 SkASSERT(0); |
| 573 } | 603 } |
| 574 } | 604 } |
| 575 | 605 |
| OLD | NEW |