|
1 |
|
2 /* |
|
3 * Copyright 2013 Google Inc. |
|
4 * |
|
5 * Use of this source code is governed by a BSD-style license that can be |
|
6 * found in the LICENSE file. |
|
7 */ |
|
8 |
|
9 #include "SkDeferredCanvas.h" |
|
10 |
|
11 #include "SkBitmapDevice.h" |
|
12 #include "SkChunkAlloc.h" |
|
13 #include "SkColorFilter.h" |
|
14 #include "SkDrawFilter.h" |
|
15 #include "SkGPipe.h" |
|
16 #include "SkPaint.h" |
|
17 #include "SkPaintPriv.h" |
|
18 #include "SkRRect.h" |
|
19 #include "SkShader.h" |
|
20 #include "SkSurface.h" |
|
21 |
|
22 enum { |
|
23 // Deferred canvas will auto-flush when recording reaches this limit |
|
24 kDefaultMaxRecordingStorageBytes = 64*1024*1024, |
|
25 kDeferredCanvasBitmapSizeThreshold = ~0U, // Disables this feature |
|
26 }; |
|
27 |
|
28 enum PlaybackMode { |
|
29 kNormal_PlaybackMode, |
|
30 kSilent_PlaybackMode, |
|
31 }; |
|
32 |
|
33 static bool shouldDrawImmediately(const SkBitmap* bitmap, const SkPaint* paint, |
|
34 size_t bitmapSizeThreshold) { |
|
35 if (bitmap && ((bitmap->getTexture() && !bitmap->isImmutable()) || |
|
36 (bitmap->getSize() > bitmapSizeThreshold))) { |
|
37 return true; |
|
38 } |
|
39 if (paint) { |
|
40 SkShader* shader = paint->getShader(); |
|
41 // Here we detect the case where the shader is an SkBitmapProcShader |
|
42 // with a gpu texture attached. Checking this without RTTI |
|
43 // requires making the assumption that only gradient shaders |
|
44 // and SkBitmapProcShader implement asABitmap(). The following |
|
45 // code may need to be revised if that assumption is ever broken. |
|
46 if (shader && !shader->asAGradient(NULL)) { |
|
47 SkBitmap bm; |
|
48 if (shader->asABitmap(&bm, NULL, NULL) && |
|
49 NULL != bm.getTexture()) { |
|
50 return true; |
|
51 } |
|
52 } |
|
53 } |
|
54 return false; |
|
55 } |
|
56 |
|
57 //----------------------------------------------------------------------------- |
|
58 // DeferredPipeController |
|
59 //----------------------------------------------------------------------------- |
|
60 |
|
61 class DeferredPipeController : public SkGPipeController { |
|
62 public: |
|
63 DeferredPipeController(); |
|
64 void setPlaybackCanvas(SkCanvas*); |
|
65 virtual ~DeferredPipeController(); |
|
66 virtual void* requestBlock(size_t minRequest, size_t* actual) SK_OVERRIDE; |
|
67 virtual void notifyWritten(size_t bytes) SK_OVERRIDE; |
|
68 void playback(bool silent); |
|
69 bool hasPendingCommands() const { return fAllocator.blockCount() != 0; } |
|
70 size_t storageAllocatedForRecording() const { return fAllocator.totalCapacity(); } |
|
71 private: |
|
72 enum { |
|
73 kMinBlockSize = 4096 |
|
74 }; |
|
75 struct PipeBlock { |
|
76 PipeBlock(void* block, size_t size) { fBlock = block, fSize = size; } |
|
77 void* fBlock; |
|
78 size_t fSize; |
|
79 }; |
|
80 void* fBlock; |
|
81 size_t fBytesWritten; |
|
82 SkChunkAlloc fAllocator; |
|
83 SkTDArray<PipeBlock> fBlockList; |
|
84 SkGPipeReader fReader; |
|
85 }; |
|
86 |
|
87 DeferredPipeController::DeferredPipeController() : |
|
88 fAllocator(kMinBlockSize) { |
|
89 fBlock = NULL; |
|
90 fBytesWritten = 0; |
|
91 } |
|
92 |
|
93 DeferredPipeController::~DeferredPipeController() { |
|
94 fAllocator.reset(); |
|
95 } |
|
96 |
|
97 void DeferredPipeController::setPlaybackCanvas(SkCanvas* canvas) { |
|
98 fReader.setCanvas(canvas); |
|
99 } |
|
100 |
|
101 void* DeferredPipeController::requestBlock(size_t minRequest, size_t *actual) { |
|
102 if (fBlock) { |
|
103 // Save the previous block for later |
|
104 PipeBlock previousBloc(fBlock, fBytesWritten); |
|
105 fBlockList.push(previousBloc); |
|
106 } |
|
107 size_t blockSize = SkTMax<size_t>(minRequest, kMinBlockSize); |
|
108 fBlock = fAllocator.allocThrow(blockSize); |
|
109 fBytesWritten = 0; |
|
110 *actual = blockSize; |
|
111 return fBlock; |
|
112 } |
|
113 |
|
114 void DeferredPipeController::notifyWritten(size_t bytes) { |
|
115 fBytesWritten += bytes; |
|
116 } |
|
117 |
|
118 void DeferredPipeController::playback(bool silent) { |
|
119 uint32_t flags = silent ? SkGPipeReader::kSilent_PlaybackFlag : 0; |
|
120 for (int currentBlock = 0; currentBlock < fBlockList.count(); currentBlock++ ) { |
|
121 fReader.playback(fBlockList[currentBlock].fBlock, fBlockList[currentBlock].fSize, |
|
122 flags); |
|
123 } |
|
124 fBlockList.reset(); |
|
125 |
|
126 if (fBlock) { |
|
127 fReader.playback(fBlock, fBytesWritten, flags); |
|
128 fBlock = NULL; |
|
129 } |
|
130 |
|
131 // Release all allocated blocks |
|
132 fAllocator.reset(); |
|
133 } |
|
134 |
|
135 //----------------------------------------------------------------------------- |
|
136 // SkDeferredDevice |
|
137 //----------------------------------------------------------------------------- |
|
138 class SkDeferredDevice : public SkBaseDevice { |
|
139 public: |
|
140 explicit SkDeferredDevice(SkSurface* surface); |
|
141 ~SkDeferredDevice(); |
|
142 |
|
143 void setNotificationClient(SkDeferredCanvas::NotificationClient* notificationClient); |
|
144 SkCanvas* recordingCanvas(); |
|
145 SkCanvas* immediateCanvas() const {return fImmediateCanvas;} |
|
146 SkBaseDevice* immediateDevice() const {return fImmediateCanvas->getTopDevice();} |
|
147 SkImage* newImageSnapshot(); |
|
148 void setSurface(SkSurface* surface); |
|
149 bool isFreshFrame(); |
|
150 bool hasPendingCommands(); |
|
151 size_t storageAllocatedForRecording() const; |
|
152 size_t freeMemoryIfPossible(size_t bytesToFree); |
|
153 size_t getBitmapSizeThreshold() const; |
|
154 void setBitmapSizeThreshold(size_t sizeThreshold); |
|
155 void flushPendingCommands(PlaybackMode); |
|
156 void skipPendingCommands(); |
|
157 void setMaxRecordingStorage(size_t); |
|
158 void recordedDrawCommand(); |
|
159 |
|
160 virtual int width() const SK_OVERRIDE; |
|
161 virtual int height() const SK_OVERRIDE; |
|
162 virtual SkBitmap::Config config() const SK_OVERRIDE; |
|
163 virtual bool isOpaque() const SK_OVERRIDE; |
|
164 virtual SkImageInfo imageInfo() const SK_OVERRIDE; |
|
165 |
|
166 virtual GrRenderTarget* accessRenderTarget() SK_OVERRIDE; |
|
167 |
|
168 virtual SkBaseDevice* onCreateDevice(const SkImageInfo&, Usage) SK_OVERRIDE; |
|
169 |
|
170 #ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG |
|
171 virtual void writePixels(const SkBitmap& bitmap, int x, int y, |
|
172 SkCanvas::Config8888 config8888) SK_OVERRIDE; |
|
173 #endif |
|
174 virtual SkSurface* newSurface(const SkImageInfo&) SK_OVERRIDE; |
|
175 |
|
176 protected: |
|
177 virtual const SkBitmap& onAccessBitmap() SK_OVERRIDE; |
|
178 virtual bool onReadPixels(const SkBitmap& bitmap, |
|
179 int x, int y, |
|
180 SkCanvas::Config8888 config8888) SK_OVERRIDE; |
|
181 virtual bool onWritePixels(const SkImageInfo&, const void*, size_t, int x, int y) SK_OVERRIDE; |
|
182 |
|
183 // The following methods are no-ops on a deferred device |
|
184 virtual bool filterTextFlags(const SkPaint& paint, TextFlags*) SK_OVERRIDE { |
|
185 return false; |
|
186 } |
|
187 |
|
188 // None of the following drawing methods should ever get called on the |
|
189 // deferred device |
|
190 virtual void clear(SkColor color) SK_OVERRIDE |
|
191 {SkASSERT(0);} |
|
192 virtual void drawPaint(const SkDraw&, const SkPaint& paint) SK_OVERRIDE |
|
193 {SkASSERT(0);} |
|
194 virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode, |
|
195 size_t count, const SkPoint[], |
|
196 const SkPaint& paint) SK_OVERRIDE |
|
197 {SkASSERT(0);} |
|
198 virtual void drawRect(const SkDraw&, const SkRect& r, |
|
199 const SkPaint& paint) SK_OVERRIDE |
|
200 {SkASSERT(0);} |
|
201 virtual void drawOval(const SkDraw&, const SkRect&, const SkPaint&) SK_OVERRIDE |
|
202 {SkASSERT(0);} |
|
203 virtual void drawRRect(const SkDraw&, const SkRRect& rr, |
|
204 const SkPaint& paint) SK_OVERRIDE |
|
205 {SkASSERT(0);} |
|
206 virtual void drawPath(const SkDraw&, const SkPath& path, |
|
207 const SkPaint& paint, |
|
208 const SkMatrix* prePathMatrix = NULL, |
|
209 bool pathIsMutable = false) SK_OVERRIDE |
|
210 {SkASSERT(0);} |
|
211 virtual void drawBitmap(const SkDraw&, const SkBitmap& bitmap, |
|
212 const SkMatrix& matrix, const SkPaint& paint) SK_OVERRIDE |
|
213 {SkASSERT(0);} |
|
214 virtual void drawBitmapRect(const SkDraw&, const SkBitmap&, const SkRect*, |
|
215 const SkRect&, const SkPaint&, |
|
216 SkCanvas::DrawBitmapRectFlags) SK_OVERRIDE |
|
217 {SkASSERT(0);} |
|
218 virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap, |
|
219 int x, int y, const SkPaint& paint) SK_OVERRIDE |
|
220 {SkASSERT(0);} |
|
221 virtual void drawText(const SkDraw&, const void* text, size_t len, |
|
222 SkScalar x, SkScalar y, const SkPaint& paint) SK_OVERRIDE |
|
223 {SkASSERT(0);} |
|
224 virtual void drawPosText(const SkDraw&, const void* text, size_t len, |
|
225 const SkScalar pos[], SkScalar constY, |
|
226 int scalarsPerPos, const SkPaint& paint) SK_OVERRIDE |
|
227 {SkASSERT(0);} |
|
228 virtual void drawTextOnPath(const SkDraw&, const void* text, |
|
229 size_t len, const SkPath& path, |
|
230 const SkMatrix* matrix, |
|
231 const SkPaint& paint) SK_OVERRIDE |
|
232 {SkASSERT(0);} |
|
233 virtual void drawVertices(const SkDraw&, SkCanvas::VertexMode, |
|
234 int vertexCount, const SkPoint verts[], |
|
235 const SkPoint texs[], const SkColor colors[], |
|
236 SkXfermode* xmode, const uint16_t indices[], |
|
237 int indexCount, const SkPaint& paint) SK_OVERRIDE |
|
238 {SkASSERT(0);} |
|
239 virtual void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y, |
|
240 const SkPaint&) SK_OVERRIDE |
|
241 {SkASSERT(0);} |
|
242 |
|
243 virtual void lockPixels() SK_OVERRIDE {} |
|
244 virtual void unlockPixels() SK_OVERRIDE {} |
|
245 |
|
246 virtual bool allowImageFilter(const SkImageFilter*) SK_OVERRIDE { |
|
247 return false; |
|
248 } |
|
249 virtual bool canHandleImageFilter(const SkImageFilter*) SK_OVERRIDE { |
|
250 return false; |
|
251 } |
|
252 virtual bool filterImage(const SkImageFilter*, const SkBitmap&, |
|
253 const SkImageFilter::Context&, SkBitmap*, SkIPoint*) SK_OVERRIDE { |
|
254 return false; |
|
255 } |
|
256 |
|
257 private: |
|
258 virtual void flush() SK_OVERRIDE; |
|
259 virtual void replaceBitmapBackendForRasterSurface(const SkBitmap&) SK_OVERRIDE {} |
|
260 |
|
261 void beginRecording(); |
|
262 void init(); |
|
263 void aboutToDraw(); |
|
264 void prepareForImmediatePixelWrite(); |
|
265 |
|
266 DeferredPipeController fPipeController; |
|
267 SkGPipeWriter fPipeWriter; |
|
268 SkCanvas* fImmediateCanvas; |
|
269 SkCanvas* fRecordingCanvas; |
|
270 SkSurface* fSurface; |
|
271 SkDeferredCanvas::NotificationClient* fNotificationClient; |
|
272 bool fFreshFrame; |
|
273 bool fCanDiscardCanvasContents; |
|
274 size_t fMaxRecordingStorageBytes; |
|
275 size_t fPreviousStorageAllocated; |
|
276 size_t fBitmapSizeThreshold; |
|
277 }; |
|
278 |
|
279 SkDeferredDevice::SkDeferredDevice(SkSurface* surface) { |
|
280 fMaxRecordingStorageBytes = kDefaultMaxRecordingStorageBytes; |
|
281 fNotificationClient = NULL; |
|
282 fImmediateCanvas = NULL; |
|
283 fSurface = NULL; |
|
284 this->setSurface(surface); |
|
285 this->init(); |
|
286 } |
|
287 |
|
288 void SkDeferredDevice::setSurface(SkSurface* surface) { |
|
289 SkRefCnt_SafeAssign(fImmediateCanvas, surface->getCanvas()); |
|
290 SkRefCnt_SafeAssign(fSurface, surface); |
|
291 fPipeController.setPlaybackCanvas(fImmediateCanvas); |
|
292 } |
|
293 |
|
294 void SkDeferredDevice::init() { |
|
295 fRecordingCanvas = NULL; |
|
296 fFreshFrame = true; |
|
297 fCanDiscardCanvasContents = false; |
|
298 fPreviousStorageAllocated = 0; |
|
299 fBitmapSizeThreshold = kDeferredCanvasBitmapSizeThreshold; |
|
300 fMaxRecordingStorageBytes = kDefaultMaxRecordingStorageBytes; |
|
301 fNotificationClient = NULL; |
|
302 this->beginRecording(); |
|
303 } |
|
304 |
|
305 SkDeferredDevice::~SkDeferredDevice() { |
|
306 this->flushPendingCommands(kSilent_PlaybackMode); |
|
307 SkSafeUnref(fImmediateCanvas); |
|
308 SkSafeUnref(fSurface); |
|
309 } |
|
310 |
|
311 void SkDeferredDevice::setMaxRecordingStorage(size_t maxStorage) { |
|
312 fMaxRecordingStorageBytes = maxStorage; |
|
313 this->recordingCanvas(); // Accessing the recording canvas applies the new limit. |
|
314 } |
|
315 |
|
316 void SkDeferredDevice::beginRecording() { |
|
317 SkASSERT(NULL == fRecordingCanvas); |
|
318 fRecordingCanvas = fPipeWriter.startRecording(&fPipeController, 0, |
|
319 immediateDevice()->width(), immediateDevice()->height()); |
|
320 } |
|
321 |
|
322 void SkDeferredDevice::setNotificationClient( |
|
323 SkDeferredCanvas::NotificationClient* notificationClient) { |
|
324 fNotificationClient = notificationClient; |
|
325 } |
|
326 |
|
327 void SkDeferredDevice::skipPendingCommands() { |
|
328 if (!fRecordingCanvas->isDrawingToLayer()) { |
|
329 fCanDiscardCanvasContents = true; |
|
330 if (fPipeController.hasPendingCommands()) { |
|
331 fFreshFrame = true; |
|
332 flushPendingCommands(kSilent_PlaybackMode); |
|
333 if (fNotificationClient) { |
|
334 fNotificationClient->skippedPendingDrawCommands(); |
|
335 } |
|
336 } |
|
337 } |
|
338 } |
|
339 |
|
340 bool SkDeferredDevice::isFreshFrame() { |
|
341 bool ret = fFreshFrame; |
|
342 fFreshFrame = false; |
|
343 return ret; |
|
344 } |
|
345 |
|
346 bool SkDeferredDevice::hasPendingCommands() { |
|
347 return fPipeController.hasPendingCommands(); |
|
348 } |
|
349 |
|
350 void SkDeferredDevice::aboutToDraw() |
|
351 { |
|
352 if (NULL != fNotificationClient) { |
|
353 fNotificationClient->prepareForDraw(); |
|
354 } |
|
355 if (fCanDiscardCanvasContents) { |
|
356 if (NULL != fSurface) { |
|
357 fSurface->notifyContentWillChange(SkSurface::kDiscard_ContentChangeMode); |
|
358 } |
|
359 fCanDiscardCanvasContents = false; |
|
360 } |
|
361 } |
|
362 |
|
363 void SkDeferredDevice::flushPendingCommands(PlaybackMode playbackMode) { |
|
364 if (!fPipeController.hasPendingCommands()) { |
|
365 return; |
|
366 } |
|
367 if (playbackMode == kNormal_PlaybackMode) { |
|
368 aboutToDraw(); |
|
369 } |
|
370 fPipeWriter.flushRecording(true); |
|
371 fPipeController.playback(kSilent_PlaybackMode == playbackMode); |
|
372 if (playbackMode == kNormal_PlaybackMode && fNotificationClient) { |
|
373 fNotificationClient->flushedDrawCommands(); |
|
374 } |
|
375 fPreviousStorageAllocated = storageAllocatedForRecording(); |
|
376 } |
|
377 |
|
378 void SkDeferredDevice::flush() { |
|
379 this->flushPendingCommands(kNormal_PlaybackMode); |
|
380 fImmediateCanvas->flush(); |
|
381 } |
|
382 |
|
383 size_t SkDeferredDevice::freeMemoryIfPossible(size_t bytesToFree) { |
|
384 size_t val = fPipeWriter.freeMemoryIfPossible(bytesToFree); |
|
385 fPreviousStorageAllocated = storageAllocatedForRecording(); |
|
386 return val; |
|
387 } |
|
388 |
|
389 size_t SkDeferredDevice::getBitmapSizeThreshold() const { |
|
390 return fBitmapSizeThreshold; |
|
391 } |
|
392 |
|
393 void SkDeferredDevice::setBitmapSizeThreshold(size_t sizeThreshold) { |
|
394 fBitmapSizeThreshold = sizeThreshold; |
|
395 } |
|
396 |
|
397 size_t SkDeferredDevice::storageAllocatedForRecording() const { |
|
398 return (fPipeController.storageAllocatedForRecording() |
|
399 + fPipeWriter.storageAllocatedForRecording()); |
|
400 } |
|
401 |
|
402 void SkDeferredDevice::recordedDrawCommand() { |
|
403 size_t storageAllocated = this->storageAllocatedForRecording(); |
|
404 |
|
405 if (storageAllocated > fMaxRecordingStorageBytes) { |
|
406 // First, attempt to reduce cache without flushing |
|
407 size_t tryFree = storageAllocated - fMaxRecordingStorageBytes; |
|
408 if (this->freeMemoryIfPossible(tryFree) < tryFree) { |
|
409 // Flush is necessary to free more space. |
|
410 this->flushPendingCommands(kNormal_PlaybackMode); |
|
411 // Free as much as possible to avoid oscillating around fMaxRecordingStorageBytes |
|
412 // which could cause a high flushing frequency. |
|
413 this->freeMemoryIfPossible(~0U); |
|
414 } |
|
415 storageAllocated = this->storageAllocatedForRecording(); |
|
416 } |
|
417 |
|
418 if (fNotificationClient && |
|
419 storageAllocated != fPreviousStorageAllocated) { |
|
420 fPreviousStorageAllocated = storageAllocated; |
|
421 fNotificationClient->storageAllocatedForRecordingChanged(storageAllocated); |
|
422 } |
|
423 } |
|
424 |
|
425 SkCanvas* SkDeferredDevice::recordingCanvas() { |
|
426 return fRecordingCanvas; |
|
427 } |
|
428 |
|
429 SkImage* SkDeferredDevice::newImageSnapshot() { |
|
430 this->flush(); |
|
431 return fSurface ? fSurface->newImageSnapshot() : NULL; |
|
432 } |
|
433 |
|
434 int SkDeferredDevice::width() const { |
|
435 return immediateDevice()->width(); |
|
436 } |
|
437 |
|
438 int SkDeferredDevice::height() const { |
|
439 return immediateDevice()->height(); |
|
440 } |
|
441 |
|
442 SkBitmap::Config SkDeferredDevice::config() const { |
|
443 return immediateDevice()->config(); |
|
444 } |
|
445 |
|
446 bool SkDeferredDevice::isOpaque() const { |
|
447 return immediateDevice()->isOpaque(); |
|
448 } |
|
449 |
|
450 SkImageInfo SkDeferredDevice::imageInfo() const { |
|
451 return immediateDevice()->imageInfo(); |
|
452 } |
|
453 |
|
454 GrRenderTarget* SkDeferredDevice::accessRenderTarget() { |
|
455 this->flushPendingCommands(kNormal_PlaybackMode); |
|
456 return immediateDevice()->accessRenderTarget(); |
|
457 } |
|
458 |
|
459 void SkDeferredDevice::prepareForImmediatePixelWrite() { |
|
460 // The purpose of the following code is to make sure commands are flushed, that |
|
461 // aboutToDraw() is called and that notifyContentWillChange is called, without |
|
462 // calling anything redundantly. |
|
463 if (fPipeController.hasPendingCommands()) { |
|
464 this->flushPendingCommands(kNormal_PlaybackMode); |
|
465 } else { |
|
466 bool mustNotifyDirectly = !fCanDiscardCanvasContents; |
|
467 this->aboutToDraw(); |
|
468 if (mustNotifyDirectly) { |
|
469 fSurface->notifyContentWillChange(SkSurface::kRetain_ContentChangeMode); |
|
470 } |
|
471 } |
|
472 |
|
473 fImmediateCanvas->flush(); |
|
474 } |
|
475 |
|
476 #ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG |
|
477 void SkDeferredDevice::writePixels(const SkBitmap& bitmap, int x, int y, |
|
478 SkCanvas::Config8888 config8888) { |
|
479 |
|
480 if (x <= 0 && y <= 0 && (x + bitmap.width()) >= width() && |
|
481 (y + bitmap.height()) >= height()) { |
|
482 this->skipPendingCommands(); |
|
483 } |
|
484 |
|
485 if (SkBitmap::kARGB_8888_Config == bitmap.config() && |
|
486 SkCanvas::kNative_Premul_Config8888 != config8888 && |
|
487 kPMColorAlias != config8888) { |
|
488 //Special case config: no deferral |
|
489 prepareForImmediatePixelWrite(); |
|
490 immediateDevice()->writePixels(bitmap, x, y, config8888); |
|
491 return; |
|
492 } |
|
493 |
|
494 SkPaint paint; |
|
495 paint.setXfermodeMode(SkXfermode::kSrc_Mode); |
|
496 if (shouldDrawImmediately(&bitmap, NULL, getBitmapSizeThreshold())) { |
|
497 prepareForImmediatePixelWrite(); |
|
498 fImmediateCanvas->drawSprite(bitmap, x, y, &paint); |
|
499 } else { |
|
500 this->recordingCanvas()->drawSprite(bitmap, x, y, &paint); |
|
501 this->recordedDrawCommand(); |
|
502 |
|
503 } |
|
504 } |
|
505 #endif |
|
506 |
|
507 bool SkDeferredDevice::onWritePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes, |
|
508 int x, int y) { |
|
509 SkASSERT(x >= 0 && y >= 0); |
|
510 SkASSERT(x + info.width() <= width()); |
|
511 SkASSERT(y + info.height() <= height()); |
|
512 |
|
513 this->flushPendingCommands(kNormal_PlaybackMode); |
|
514 |
|
515 const SkImageInfo deviceInfo = this->imageInfo(); |
|
516 if (info.width() == deviceInfo.width() && info.height() == deviceInfo.height()) { |
|
517 this->skipPendingCommands(); |
|
518 } |
|
519 |
|
520 this->prepareForImmediatePixelWrite(); |
|
521 return immediateDevice()->onWritePixels(info, pixels, rowBytes, x, y); |
|
522 } |
|
523 |
|
524 const SkBitmap& SkDeferredDevice::onAccessBitmap() { |
|
525 this->flushPendingCommands(kNormal_PlaybackMode); |
|
526 return immediateDevice()->accessBitmap(false); |
|
527 } |
|
528 |
|
529 SkBaseDevice* SkDeferredDevice::onCreateDevice(const SkImageInfo& info, Usage usage) { |
|
530 // Save layer usage not supported, and not required by SkDeferredCanvas. |
|
531 SkASSERT(usage != kSaveLayer_Usage); |
|
532 // Create a compatible non-deferred device. |
|
533 // We do not create a deferred device because we know the new device |
|
534 // will not be used with a deferred canvas (there is no API for that). |
|
535 // And connecting a SkDeferredDevice to non-deferred canvas can result |
|
536 // in unpredictable behavior. |
|
537 return immediateDevice()->createCompatibleDevice(info); |
|
538 } |
|
539 |
|
540 SkSurface* SkDeferredDevice::newSurface(const SkImageInfo& info) { |
|
541 return this->immediateDevice()->newSurface(info); |
|
542 } |
|
543 |
|
544 bool SkDeferredDevice::onReadPixels( |
|
545 const SkBitmap& bitmap, int x, int y, SkCanvas::Config8888 config8888) { |
|
546 this->flushPendingCommands(kNormal_PlaybackMode); |
|
547 return fImmediateCanvas->readPixels(const_cast<SkBitmap*>(&bitmap), |
|
548 x, y, config8888); |
|
549 } |
|
550 |
|
551 class AutoImmediateDrawIfNeeded { |
|
552 public: |
|
553 AutoImmediateDrawIfNeeded(SkDeferredCanvas& canvas, const SkBitmap* bitmap, |
|
554 const SkPaint* paint) { |
|
555 this->init(canvas, bitmap, paint); |
|
556 } |
|
557 |
|
558 AutoImmediateDrawIfNeeded(SkDeferredCanvas& canvas, const SkPaint* paint) { |
|
559 this->init(canvas, NULL, paint); |
|
560 } |
|
561 |
|
562 ~AutoImmediateDrawIfNeeded() { |
|
563 if (fCanvas) { |
|
564 fCanvas->setDeferredDrawing(true); |
|
565 } |
|
566 } |
|
567 private: |
|
568 void init(SkDeferredCanvas& canvas, const SkBitmap* bitmap, const SkPaint* paint) |
|
569 { |
|
570 SkDeferredDevice* device = static_cast<SkDeferredDevice*>(canvas.getDevice()); |
|
571 if (canvas.isDeferredDrawing() && (NULL != device) && |
|
572 shouldDrawImmediately(bitmap, paint, device->getBitmapSizeThreshold())) { |
|
573 canvas.setDeferredDrawing(false); |
|
574 fCanvas = &canvas; |
|
575 } else { |
|
576 fCanvas = NULL; |
|
577 } |
|
578 } |
|
579 |
|
580 SkDeferredCanvas* fCanvas; |
|
581 }; |
|
582 |
|
583 SkDeferredCanvas* SkDeferredCanvas::Create(SkSurface* surface) { |
|
584 SkAutoTUnref<SkDeferredDevice> deferredDevice(SkNEW_ARGS(SkDeferredDevice, (surface))); |
|
585 return SkNEW_ARGS(SkDeferredCanvas, (deferredDevice)); |
|
586 } |
|
587 |
|
588 SkDeferredCanvas::SkDeferredCanvas(SkDeferredDevice* device) : SkCanvas (device) { |
|
589 this->init(); |
|
590 } |
|
591 |
|
592 void SkDeferredCanvas::init() { |
|
593 fDeferredDrawing = true; // On by default |
|
594 } |
|
595 |
|
596 void SkDeferredCanvas::setMaxRecordingStorage(size_t maxStorage) { |
|
597 this->validate(); |
|
598 this->getDeferredDevice()->setMaxRecordingStorage(maxStorage); |
|
599 } |
|
600 |
|
601 size_t SkDeferredCanvas::storageAllocatedForRecording() const { |
|
602 return this->getDeferredDevice()->storageAllocatedForRecording(); |
|
603 } |
|
604 |
|
605 size_t SkDeferredCanvas::freeMemoryIfPossible(size_t bytesToFree) { |
|
606 return this->getDeferredDevice()->freeMemoryIfPossible(bytesToFree); |
|
607 } |
|
608 |
|
609 void SkDeferredCanvas::setBitmapSizeThreshold(size_t sizeThreshold) { |
|
610 SkDeferredDevice* deferredDevice = this->getDeferredDevice(); |
|
611 SkASSERT(deferredDevice); |
|
612 deferredDevice->setBitmapSizeThreshold(sizeThreshold); |
|
613 } |
|
614 |
|
615 void SkDeferredCanvas::recordedDrawCommand() { |
|
616 if (fDeferredDrawing) { |
|
617 this->getDeferredDevice()->recordedDrawCommand(); |
|
618 } |
|
619 } |
|
620 |
|
621 void SkDeferredCanvas::validate() const { |
|
622 SkASSERT(this->getDevice()); |
|
623 } |
|
624 |
|
625 SkCanvas* SkDeferredCanvas::drawingCanvas() const { |
|
626 this->validate(); |
|
627 return fDeferredDrawing ? this->getDeferredDevice()->recordingCanvas() : |
|
628 this->getDeferredDevice()->immediateCanvas(); |
|
629 } |
|
630 |
|
631 SkCanvas* SkDeferredCanvas::immediateCanvas() const { |
|
632 this->validate(); |
|
633 return this->getDeferredDevice()->immediateCanvas(); |
|
634 } |
|
635 |
|
636 SkDeferredDevice* SkDeferredCanvas::getDeferredDevice() const { |
|
637 return static_cast<SkDeferredDevice*>(this->getDevice()); |
|
638 } |
|
639 |
|
640 void SkDeferredCanvas::setDeferredDrawing(bool val) { |
|
641 this->validate(); // Must set device before calling this method |
|
642 if (val != fDeferredDrawing) { |
|
643 if (fDeferredDrawing) { |
|
644 // Going live. |
|
645 this->getDeferredDevice()->flushPendingCommands(kNormal_PlaybackMode); |
|
646 } |
|
647 fDeferredDrawing = val; |
|
648 } |
|
649 } |
|
650 |
|
651 bool SkDeferredCanvas::isDeferredDrawing() const { |
|
652 return fDeferredDrawing; |
|
653 } |
|
654 |
|
655 bool SkDeferredCanvas::isFreshFrame() const { |
|
656 return this->getDeferredDevice()->isFreshFrame(); |
|
657 } |
|
658 |
|
659 bool SkDeferredCanvas::hasPendingCommands() const { |
|
660 return this->getDeferredDevice()->hasPendingCommands(); |
|
661 } |
|
662 |
|
663 void SkDeferredCanvas::silentFlush() { |
|
664 if (fDeferredDrawing) { |
|
665 this->getDeferredDevice()->flushPendingCommands(kSilent_PlaybackMode); |
|
666 } |
|
667 } |
|
668 |
|
669 SkDeferredCanvas::~SkDeferredCanvas() { |
|
670 } |
|
671 |
|
672 SkSurface* SkDeferredCanvas::setSurface(SkSurface* surface) { |
|
673 SkDeferredDevice* deferredDevice = this->getDeferredDevice(); |
|
674 SkASSERT(NULL != deferredDevice); |
|
675 // By swapping the surface into the existing device, we preserve |
|
676 // all pending commands, which can help to seamlessly recover from |
|
677 // a lost accelerated graphics context. |
|
678 deferredDevice->setSurface(surface); |
|
679 return surface; |
|
680 } |
|
681 |
|
682 SkDeferredCanvas::NotificationClient* SkDeferredCanvas::setNotificationClient( |
|
683 NotificationClient* notificationClient) { |
|
684 |
|
685 SkDeferredDevice* deferredDevice = this->getDeferredDevice(); |
|
686 SkASSERT(deferredDevice); |
|
687 if (deferredDevice) { |
|
688 deferredDevice->setNotificationClient(notificationClient); |
|
689 } |
|
690 return notificationClient; |
|
691 } |
|
692 |
|
693 SkImage* SkDeferredCanvas::newImageSnapshot() { |
|
694 SkDeferredDevice* deferredDevice = this->getDeferredDevice(); |
|
695 SkASSERT(deferredDevice); |
|
696 return deferredDevice ? deferredDevice->newImageSnapshot() : NULL; |
|
697 } |
|
698 |
|
699 bool SkDeferredCanvas::isFullFrame(const SkRect* rect, |
|
700 const SkPaint* paint) const { |
|
701 SkCanvas* canvas = this->drawingCanvas(); |
|
702 SkISize canvasSize = this->getDeviceSize(); |
|
703 if (rect) { |
|
704 if (!canvas->getTotalMatrix().rectStaysRect()) { |
|
705 return false; // conservative |
|
706 } |
|
707 |
|
708 SkRect transformedRect; |
|
709 canvas->getTotalMatrix().mapRect(&transformedRect, *rect); |
|
710 |
|
711 if (paint) { |
|
712 SkPaint::Style paintStyle = paint->getStyle(); |
|
713 if (!(paintStyle == SkPaint::kFill_Style || |
|
714 paintStyle == SkPaint::kStrokeAndFill_Style)) { |
|
715 return false; |
|
716 } |
|
717 if (paint->getMaskFilter() || paint->getLooper() |
|
718 || paint->getPathEffect() || paint->getImageFilter()) { |
|
719 return false; // conservative |
|
720 } |
|
721 } |
|
722 |
|
723 // The following test holds with AA enabled, and is conservative |
|
724 // by a 0.5 pixel margin with AA disabled |
|
725 if (transformedRect.fLeft > SkIntToScalar(0) || |
|
726 transformedRect.fTop > SkIntToScalar(0) || |
|
727 transformedRect.fRight < SkIntToScalar(canvasSize.fWidth) || |
|
728 transformedRect.fBottom < SkIntToScalar(canvasSize.fHeight)) { |
|
729 return false; |
|
730 } |
|
731 } |
|
732 |
|
733 return this->getClipStack()->quickContains(SkRect::MakeXYWH(0, 0, |
|
734 SkIntToScalar(canvasSize.fWidth), SkIntToScalar(canvasSize.fHeight))); |
|
735 } |
|
736 |
|
737 void SkDeferredCanvas::willSave(SaveFlags flags) { |
|
738 this->drawingCanvas()->save(flags); |
|
739 this->recordedDrawCommand(); |
|
740 this->INHERITED::willSave(flags); |
|
741 } |
|
742 |
|
743 SkCanvas::SaveLayerStrategy SkDeferredCanvas::willSaveLayer(const SkRect* bounds, |
|
744 const SkPaint* paint, SaveFlags flags) { |
|
745 this->drawingCanvas()->saveLayer(bounds, paint, flags); |
|
746 this->recordedDrawCommand(); |
|
747 this->INHERITED::willSaveLayer(bounds, paint, flags); |
|
748 // No need for a full layer. |
|
749 return kNoLayer_SaveLayerStrategy; |
|
750 } |
|
751 |
|
752 void SkDeferredCanvas::willRestore() { |
|
753 this->drawingCanvas()->restore(); |
|
754 this->recordedDrawCommand(); |
|
755 this->INHERITED::willRestore(); |
|
756 } |
|
757 |
|
758 bool SkDeferredCanvas::isDrawingToLayer() const { |
|
759 return this->drawingCanvas()->isDrawingToLayer(); |
|
760 } |
|
761 |
|
762 void SkDeferredCanvas::didTranslate(SkScalar dx, SkScalar dy) { |
|
763 this->drawingCanvas()->translate(dx, dy); |
|
764 this->recordedDrawCommand(); |
|
765 this->INHERITED::didTranslate(dx, dy); |
|
766 } |
|
767 |
|
768 void SkDeferredCanvas::didScale(SkScalar sx, SkScalar sy) { |
|
769 this->drawingCanvas()->scale(sx, sy); |
|
770 this->recordedDrawCommand(); |
|
771 this->INHERITED::didScale(sx, sy); |
|
772 } |
|
773 |
|
774 void SkDeferredCanvas::didRotate(SkScalar degrees) { |
|
775 this->drawingCanvas()->rotate(degrees); |
|
776 this->recordedDrawCommand(); |
|
777 this->INHERITED::didRotate(degrees); |
|
778 } |
|
779 |
|
780 void SkDeferredCanvas::didSkew(SkScalar sx, SkScalar sy) { |
|
781 this->drawingCanvas()->skew(sx, sy); |
|
782 this->recordedDrawCommand(); |
|
783 this->INHERITED::didSkew(sx, sy); |
|
784 } |
|
785 |
|
786 void SkDeferredCanvas::didConcat(const SkMatrix& matrix) { |
|
787 this->drawingCanvas()->concat(matrix); |
|
788 this->recordedDrawCommand(); |
|
789 this->INHERITED::didConcat(matrix); |
|
790 } |
|
791 |
|
792 void SkDeferredCanvas::didSetMatrix(const SkMatrix& matrix) { |
|
793 this->drawingCanvas()->setMatrix(matrix); |
|
794 this->recordedDrawCommand(); |
|
795 this->INHERITED::didSetMatrix(matrix); |
|
796 } |
|
797 |
|
798 void SkDeferredCanvas::onClipRect(const SkRect& rect, |
|
799 SkRegion::Op op, |
|
800 ClipEdgeStyle edgeStyle) { |
|
801 this->drawingCanvas()->clipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle); |
|
802 this->INHERITED::onClipRect(rect, op, edgeStyle); |
|
803 this->recordedDrawCommand(); |
|
804 } |
|
805 |
|
806 void SkDeferredCanvas::onClipRRect(const SkRRect& rrect, |
|
807 SkRegion::Op op, |
|
808 ClipEdgeStyle edgeStyle) { |
|
809 this->drawingCanvas()->clipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle); |
|
810 this->INHERITED::onClipRRect(rrect, op, edgeStyle); |
|
811 this->recordedDrawCommand(); |
|
812 } |
|
813 |
|
814 void SkDeferredCanvas::onClipPath(const SkPath& path, |
|
815 SkRegion::Op op, |
|
816 ClipEdgeStyle edgeStyle) { |
|
817 this->drawingCanvas()->clipPath(path, op, kSoft_ClipEdgeStyle == edgeStyle); |
|
818 this->INHERITED::onClipPath(path, op, edgeStyle); |
|
819 this->recordedDrawCommand(); |
|
820 } |
|
821 |
|
822 void SkDeferredCanvas::onClipRegion(const SkRegion& deviceRgn, SkRegion::Op op) { |
|
823 this->drawingCanvas()->clipRegion(deviceRgn, op); |
|
824 this->INHERITED::onClipRegion(deviceRgn, op); |
|
825 this->recordedDrawCommand(); |
|
826 } |
|
827 |
|
828 void SkDeferredCanvas::clear(SkColor color) { |
|
829 // purge pending commands |
|
830 if (fDeferredDrawing) { |
|
831 this->getDeferredDevice()->skipPendingCommands(); |
|
832 } |
|
833 |
|
834 this->drawingCanvas()->clear(color); |
|
835 this->recordedDrawCommand(); |
|
836 } |
|
837 |
|
838 void SkDeferredCanvas::drawPaint(const SkPaint& paint) { |
|
839 if (fDeferredDrawing && this->isFullFrame(NULL, &paint) && |
|
840 isPaintOpaque(&paint)) { |
|
841 this->getDeferredDevice()->skipPendingCommands(); |
|
842 } |
|
843 AutoImmediateDrawIfNeeded autoDraw(*this, &paint); |
|
844 this->drawingCanvas()->drawPaint(paint); |
|
845 this->recordedDrawCommand(); |
|
846 } |
|
847 |
|
848 void SkDeferredCanvas::drawPoints(PointMode mode, size_t count, |
|
849 const SkPoint pts[], const SkPaint& paint) { |
|
850 AutoImmediateDrawIfNeeded autoDraw(*this, &paint); |
|
851 this->drawingCanvas()->drawPoints(mode, count, pts, paint); |
|
852 this->recordedDrawCommand(); |
|
853 } |
|
854 |
|
855 void SkDeferredCanvas::drawOval(const SkRect& rect, const SkPaint& paint) { |
|
856 AutoImmediateDrawIfNeeded autoDraw(*this, &paint); |
|
857 this->drawingCanvas()->drawOval(rect, paint); |
|
858 this->recordedDrawCommand(); |
|
859 } |
|
860 |
|
861 void SkDeferredCanvas::drawRect(const SkRect& rect, const SkPaint& paint) { |
|
862 if (fDeferredDrawing && this->isFullFrame(&rect, &paint) && |
|
863 isPaintOpaque(&paint)) { |
|
864 this->getDeferredDevice()->skipPendingCommands(); |
|
865 } |
|
866 |
|
867 AutoImmediateDrawIfNeeded autoDraw(*this, &paint); |
|
868 this->drawingCanvas()->drawRect(rect, paint); |
|
869 this->recordedDrawCommand(); |
|
870 } |
|
871 |
|
872 void SkDeferredCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) { |
|
873 if (rrect.isRect()) { |
|
874 this->SkDeferredCanvas::drawRect(rrect.getBounds(), paint); |
|
875 } else if (rrect.isOval()) { |
|
876 this->SkDeferredCanvas::drawOval(rrect.getBounds(), paint); |
|
877 } else { |
|
878 AutoImmediateDrawIfNeeded autoDraw(*this, &paint); |
|
879 this->drawingCanvas()->drawRRect(rrect, paint); |
|
880 this->recordedDrawCommand(); |
|
881 } |
|
882 } |
|
883 |
|
884 void SkDeferredCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, |
|
885 const SkPaint& paint) { |
|
886 AutoImmediateDrawIfNeeded autoDraw(*this, &paint); |
|
887 this->drawingCanvas()->drawDRRect(outer, inner, paint); |
|
888 this->recordedDrawCommand(); |
|
889 } |
|
890 |
|
891 void SkDeferredCanvas::drawPath(const SkPath& path, const SkPaint& paint) { |
|
892 AutoImmediateDrawIfNeeded autoDraw(*this, &paint); |
|
893 this->drawingCanvas()->drawPath(path, paint); |
|
894 this->recordedDrawCommand(); |
|
895 } |
|
896 |
|
897 void SkDeferredCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left, |
|
898 SkScalar top, const SkPaint* paint) { |
|
899 SkRect bitmapRect = SkRect::MakeXYWH(left, top, |
|
900 SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height())); |
|
901 if (fDeferredDrawing && |
|
902 this->isFullFrame(&bitmapRect, paint) && |
|
903 isPaintOpaque(paint, &bitmap)) { |
|
904 this->getDeferredDevice()->skipPendingCommands(); |
|
905 } |
|
906 |
|
907 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint); |
|
908 this->drawingCanvas()->drawBitmap(bitmap, left, top, paint); |
|
909 this->recordedDrawCommand(); |
|
910 } |
|
911 |
|
912 void SkDeferredCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, |
|
913 const SkRect* src, |
|
914 const SkRect& dst, |
|
915 const SkPaint* paint, |
|
916 DrawBitmapRectFlags flags) { |
|
917 if (fDeferredDrawing && |
|
918 this->isFullFrame(&dst, paint) && |
|
919 isPaintOpaque(paint, &bitmap)) { |
|
920 this->getDeferredDevice()->skipPendingCommands(); |
|
921 } |
|
922 |
|
923 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint); |
|
924 this->drawingCanvas()->drawBitmapRectToRect(bitmap, src, dst, paint, flags); |
|
925 this->recordedDrawCommand(); |
|
926 } |
|
927 |
|
928 |
|
929 void SkDeferredCanvas::drawBitmapMatrix(const SkBitmap& bitmap, |
|
930 const SkMatrix& m, |
|
931 const SkPaint* paint) { |
|
932 // TODO: reset recording canvas if paint+bitmap is opaque and clip rect |
|
933 // covers canvas entirely and transformed bitmap covers canvas entirely |
|
934 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint); |
|
935 this->drawingCanvas()->drawBitmapMatrix(bitmap, m, paint); |
|
936 this->recordedDrawCommand(); |
|
937 } |
|
938 |
|
939 void SkDeferredCanvas::drawBitmapNine(const SkBitmap& bitmap, |
|
940 const SkIRect& center, const SkRect& dst, |
|
941 const SkPaint* paint) { |
|
942 // TODO: reset recording canvas if paint+bitmap is opaque and clip rect |
|
943 // covers canvas entirely and dst covers canvas entirely |
|
944 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint); |
|
945 this->drawingCanvas()->drawBitmapNine(bitmap, center, dst, paint); |
|
946 this->recordedDrawCommand(); |
|
947 } |
|
948 |
|
949 void SkDeferredCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, |
|
950 const SkPaint* paint) { |
|
951 SkRect bitmapRect = SkRect::MakeXYWH( |
|
952 SkIntToScalar(left), |
|
953 SkIntToScalar(top), |
|
954 SkIntToScalar(bitmap.width()), |
|
955 SkIntToScalar(bitmap.height())); |
|
956 if (fDeferredDrawing && |
|
957 this->isFullFrame(&bitmapRect, paint) && |
|
958 isPaintOpaque(paint, &bitmap)) { |
|
959 this->getDeferredDevice()->skipPendingCommands(); |
|
960 } |
|
961 |
|
962 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint); |
|
963 this->drawingCanvas()->drawSprite(bitmap, left, top, paint); |
|
964 this->recordedDrawCommand(); |
|
965 } |
|
966 |
|
967 void SkDeferredCanvas::drawText(const void* text, size_t byteLength, |
|
968 SkScalar x, SkScalar y, const SkPaint& paint) { |
|
969 AutoImmediateDrawIfNeeded autoDraw(*this, &paint); |
|
970 this->drawingCanvas()->drawText(text, byteLength, x, y, paint); |
|
971 this->recordedDrawCommand(); |
|
972 } |
|
973 |
|
974 void SkDeferredCanvas::drawPosText(const void* text, size_t byteLength, |
|
975 const SkPoint pos[], const SkPaint& paint) { |
|
976 AutoImmediateDrawIfNeeded autoDraw(*this, &paint); |
|
977 this->drawingCanvas()->drawPosText(text, byteLength, pos, paint); |
|
978 this->recordedDrawCommand(); |
|
979 } |
|
980 |
|
981 void SkDeferredCanvas::drawPosTextH(const void* text, size_t byteLength, |
|
982 const SkScalar xpos[], SkScalar constY, |
|
983 const SkPaint& paint) { |
|
984 AutoImmediateDrawIfNeeded autoDraw(*this, &paint); |
|
985 this->drawingCanvas()->drawPosTextH(text, byteLength, xpos, constY, paint); |
|
986 this->recordedDrawCommand(); |
|
987 } |
|
988 |
|
989 void SkDeferredCanvas::drawTextOnPath(const void* text, size_t byteLength, |
|
990 const SkPath& path, |
|
991 const SkMatrix* matrix, |
|
992 const SkPaint& paint) { |
|
993 AutoImmediateDrawIfNeeded autoDraw(*this, &paint); |
|
994 this->drawingCanvas()->drawTextOnPath(text, byteLength, path, matrix, paint); |
|
995 this->recordedDrawCommand(); |
|
996 } |
|
997 |
|
998 void SkDeferredCanvas::drawPicture(SkPicture& picture) { |
|
999 this->drawingCanvas()->drawPicture(picture); |
|
1000 this->recordedDrawCommand(); |
|
1001 } |
|
1002 |
|
1003 void SkDeferredCanvas::drawVertices(VertexMode vmode, int vertexCount, |
|
1004 const SkPoint vertices[], |
|
1005 const SkPoint texs[], |
|
1006 const SkColor colors[], SkXfermode* xmode, |
|
1007 const uint16_t indices[], int indexCount, |
|
1008 const SkPaint& paint) { |
|
1009 AutoImmediateDrawIfNeeded autoDraw(*this, &paint); |
|
1010 this->drawingCanvas()->drawVertices(vmode, vertexCount, vertices, texs, colors, xmode, |
|
1011 indices, indexCount, paint); |
|
1012 this->recordedDrawCommand(); |
|
1013 } |
|
1014 |
|
1015 SkBounder* SkDeferredCanvas::setBounder(SkBounder* bounder) { |
|
1016 this->drawingCanvas()->setBounder(bounder); |
|
1017 this->INHERITED::setBounder(bounder); |
|
1018 this->recordedDrawCommand(); |
|
1019 return bounder; |
|
1020 } |
|
1021 |
|
1022 SkDrawFilter* SkDeferredCanvas::setDrawFilter(SkDrawFilter* filter) { |
|
1023 this->drawingCanvas()->setDrawFilter(filter); |
|
1024 this->INHERITED::setDrawFilter(filter); |
|
1025 this->recordedDrawCommand(); |
|
1026 return filter; |
|
1027 } |
|
1028 |
|
1029 SkCanvas* SkDeferredCanvas::canvasForDrawIter() { |
|
1030 return this->drawingCanvas(); |
|
1031 } |