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 // If 'iter' is valid use it to skip forward through the picture. | |
141 void SkPicturePlayback::StepIterator(SkPictureStateTree::Iterator* iter, SkReade r32* reader) { | |
142 if (iter->isValid()) { | |
143 uint32_t skipTo = iter->nextDraw(); | |
144 if (SkPictureStateTree::Iterator::kDrawComplete == skipTo) { | |
145 reader->setOffset(reader->size()); // skip to end | |
146 } else { | |
147 reader->setOffset(skipTo); | |
148 } | |
149 } | |
150 } | |
151 | |
152 bool SkPicturePlayback::replaceOps(SkPictureStateTree::Iterator* iter, | |
153 SkReader32* reader, | |
154 SkCanvas* canvas, | |
155 const SkMatrix& initialMatrix) { | |
156 if (NULL != fReplacements) { | |
157 // Potentially replace a block of operations with a single drawBitmap ca ll | |
158 SkPicturePlayback::PlaybackReplacements::ReplacementInfo* temp = | |
159 fReplacements->lookupByStart(reader- >offset()); | |
160 if (NULL != temp) { | |
161 SkASSERT(NULL != temp->fBM); | |
162 SkASSERT(NULL != temp->fPaint); | |
163 canvas->save(); | |
164 canvas->setMatrix(initialMatrix); | |
165 SkRect src = SkRect::Make(temp->fSrcRect); | |
166 SkRect dst = SkRect::MakeXYWH(temp->fPos.fX, temp->fPos.fY, | |
167 temp->fSrcRect.width(), | |
168 temp->fSrcRect.height()); | |
169 canvas->drawBitmapRectToRect(*temp->fBM, &src, dst, temp->fPaint); | |
170 canvas->restore(); | |
171 | |
172 if (iter->isValid()) { | |
173 // This save is needed since the BBH will automatically issue | |
174 // a restore to balanced the saveLayer we're skipping | |
175 canvas->save(); | |
176 | |
177 // At this point we know that the PictureStateTree was aiming | |
178 // for some draw op within temp's saveLayer (although potentiall y | |
179 // in a separate saveLayer nested inside it). | |
180 // We need to skip all the operations inside temp's range | |
181 // along with all the associated state changes but update | |
182 // the state tree to the first operation outside temp's range. | |
183 | |
184 uint32_t skipTo; | |
185 do { | |
186 skipTo = iter->nextDraw(); | |
187 if (SkPictureStateTree::Iterator::kDrawComplete == skipTo) { | |
188 break; | |
189 } | |
190 | |
191 if (skipTo <= temp->fStop) { | |
192 reader->setOffset(skipTo); | |
193 uint32_t size; | |
194 DrawType op = ReadOpAndSize(reader, &size); | |
195 // Since we are relying on the normal SkPictureStateTree | |
196 // playback we need to convert any nested saveLayer call s | |
197 // it may issue into saves (so that all its internal | |
198 // restores will be balanced). | |
199 if (SAVE_LAYER == op) { | |
200 canvas->save(); | |
201 } | |
202 } | |
203 } while (skipTo <= temp->fStop); | |
204 | |
205 if (SkPictureStateTree::Iterator::kDrawComplete == skipTo) { | |
206 reader->setOffset(reader->size()); // skip to end | |
207 return true; | |
131 } | 208 } |
132 | 209 |
133 activeOps = &(activeOpsList.get()->fOps); | 210 reader->setOffset(skipTo); |
211 } else { | |
212 reader->setOffset(temp->fStop); | |
213 uint32_t size; | |
214 SkDEBUGCODE(DrawType op = ) ReadOpAndSize(reader, &size); | |
215 SkASSERT(RESTORE == op); | |
134 } | 216 } |
217 | |
218 return true; | |
135 } | 219 } |
136 } | 220 } |
137 | 221 |
138 SkPictureStateTree::Iterator it = (NULL == activeOps) ? | 222 return false; |
139 SkPictureStateTree::Iterator() : | 223 } |
140 fPictureData->fStateTree->getIterator(*activeOps, canvas); | |
141 | 224 |
142 if (it.isValid()) { | 225 // Update the iterator and state tree to catch up with the skipped ops. |
143 uint32_t skipTo = it.nextDraw(); | 226 void SkPicturePlayback::SkipIterTo(SkPictureStateTree::Iterator* iter, |
144 if (kDrawComplete == skipTo) { | 227 SkReader32* reader, |
145 return; | 228 uint32_t skipTo) { |
146 } | 229 if (iter->isValid()) { |
147 reader.setOffset(skipTo); | 230 // If using a bounding box hierarchy, advance the state tree |
231 // iterator until at or after skipTo | |
232 uint32_t adjustedSkipTo; | |
233 do { | |
234 adjustedSkipTo = iter->nextDraw(); | |
235 } while (adjustedSkipTo < skipTo); | |
236 skipTo = adjustedSkipTo; | |
148 } | 237 } |
238 if (SkPictureStateTree::Iterator::kDrawComplete == skipTo) { | |
mtklein
2014/07/09 17:55:01
Is there any chance we could have passed this whil
robertphillips
2014/07/09 18:12:39
skipTo will never be kDrawComplete on entry (I'll
| |
239 reader->setOffset(reader->size()); // skip to end | |
240 } else { | |
241 reader->setOffset(skipTo); | |
242 } | |
243 } | |
244 | |
245 void SkPicturePlayback::draw(SkCanvas* canvas, SkDrawPictureCallback* callback) { | |
246 AutoResetOpID aroi(this); | |
247 SkASSERT(0 == fCurOffset); | |
248 | |
249 SkAutoTDelete<const SkPicture::OperationList> activeOpsList(this->getActiveO ps(canvas)); | |
250 SkPictureStateTree::Iterator it; | |
251 | |
252 if (!this->initIterator(&it, canvas, activeOpsList.get())) { | |
253 return; // nothing to draw | |
254 } | |
255 | |
256 SkReader32 reader(fPictureData->opData()->bytes(), fPictureData->opData()->s ize()); | |
257 | |
258 StepIterator(&it, &reader); | |
149 | 259 |
150 // Record this, so we can concat w/ it if we encounter a setMatrix() | 260 // Record this, so we can concat w/ it if we encounter a setMatrix() |
151 SkMatrix initialMatrix = canvas->getTotalMatrix(); | 261 SkMatrix initialMatrix = canvas->getTotalMatrix(); |
152 | 262 |
153 SkAutoCanvasRestore acr(canvas, false); | 263 SkAutoCanvasRestore acr(canvas, false); |
154 | 264 |
155 while (!reader.eof()) { | 265 while (!reader.eof()) { |
156 if (callback && callback->abortDrawing()) { | 266 if (NULL != callback && callback->abortDrawing()) { |
157 return; | 267 return; |
158 } | 268 } |
159 | 269 |
160 if (NULL != fReplacements) { | 270 if (this->replaceOps(&it, &reader, canvas, initialMatrix)) { |
161 // Potentially replace a block of operations with a single drawBitma p call | 271 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 } | 272 } |
223 | 273 |
224 fCurOffset = reader.offset(); | 274 fCurOffset = reader.offset(); |
225 uint32_t size; | 275 uint32_t size; |
226 DrawType op = ReadOpAndSize(&reader, &size); | 276 DrawType op = ReadOpAndSize(&reader, &size); |
227 size_t skipTo = 0; | |
228 if (NOOP == op) { | 277 if (NOOP == op) { |
229 // NOOPs are to be ignored - do not propagate them any further | 278 // NOOPs are to be ignored - do not propagate them any further |
230 skipTo = fCurOffset + size; | 279 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; | 280 continue; |
248 } | 281 } |
249 | 282 |
250 this->handleOp(&reader, op, size, canvas, initialMatrix); | 283 this->handleOp(&reader, op, size, canvas, initialMatrix); |
251 | 284 |
252 if (it.isValid()) { | 285 StepIterator(&it, &reader); |
253 uint32_t skipTo = it.nextDraw(); | |
254 if (kDrawComplete == skipTo) { | |
255 break; | |
256 } | |
257 reader.setOffset(skipTo); | |
258 } | |
259 } | 286 } |
260 } | 287 } |
261 | 288 |
262 void SkPicturePlayback::handleOp(SkReader32* reader, | 289 void SkPicturePlayback::handleOp(SkReader32* reader, |
263 DrawType op, | 290 DrawType op, |
264 uint32_t size, | 291 uint32_t size, |
265 SkCanvas* canvas, | 292 SkCanvas* canvas, |
266 const SkMatrix& initialMatrix) { | 293 const SkMatrix& initialMatrix) { |
267 switch (op) { | 294 switch (op) { |
268 case CLIP_PATH: { | 295 case CLIP_PATH: { |
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
566 case TRANSLATE: { | 593 case TRANSLATE: { |
567 SkScalar dx = reader->readScalar(); | 594 SkScalar dx = reader->readScalar(); |
568 SkScalar dy = reader->readScalar(); | 595 SkScalar dy = reader->readScalar(); |
569 canvas->translate(dx, dy); | 596 canvas->translate(dx, dy); |
570 } break; | 597 } break; |
571 default: | 598 default: |
572 SkASSERT(0); | 599 SkASSERT(0); |
573 } | 600 } |
574 } | 601 } |
575 | 602 |
OLD | NEW |