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 |