• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * Copyright 2011 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 "SkPaint.h"
12 #include "SkShader.h"
13 #include "SkColorFilter.h"
14 #include "SkDrawFilter.h"
15 
16 namespace {
17 
isPaintOpaque(const SkPaint * paint,const SkBitmap * bmpReplacesShader=NULL)18 bool isPaintOpaque(const SkPaint* paint,
19                    const SkBitmap* bmpReplacesShader = NULL) {
20     // TODO: SkXfermode should have a virtual isOpaque method, which would
21     // make it possible to test modes that do not have a Coeff representation.
22 
23     if (!paint) {
24         return bmpReplacesShader ? bmpReplacesShader->isOpaque() : true;
25     }
26 
27     SkXfermode::Coeff srcCoeff, dstCoeff;
28     if (SkXfermode::AsCoeff(paint->getXfermode(), &srcCoeff, &dstCoeff)){
29         switch (dstCoeff) {
30         case SkXfermode::kZero_Coeff:
31             return true;
32         case SkXfermode::kISA_Coeff:
33             if (paint->getAlpha() != 255) {
34                 break;
35             }
36             if (bmpReplacesShader) {
37                 if (!bmpReplacesShader->isOpaque()) {
38                     break;
39                 }
40             } else if (paint->getShader() && !paint->getShader()->isOpaque()) {
41                 break;
42             }
43             if (paint->getColorFilter() &&
44                 ((paint->getColorFilter()->getFlags() &
45                 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
46                 break;
47             }
48             return true;
49         case SkXfermode::kSA_Coeff:
50             if (paint->getAlpha() != 0) {
51                 break;
52             }
53             if (paint->getColorFilter() &&
54                 ((paint->getColorFilter()->getFlags() &
55                 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
56                 break;
57             }
58             return true;
59         case SkXfermode::kSC_Coeff:
60             if (paint->getColor() != 0) { // all components must be 0
61                 break;
62             }
63             if (bmpReplacesShader || paint->getShader()) {
64                 break;
65             }
66             if (paint->getColorFilter() && (
67                 (paint->getColorFilter()->getFlags() &
68                 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
69                 break;
70             }
71             return true;
72         default:
73             break;
74         }
75     }
76     return false;
77 }
78 
79 } // unnamed namespace
80 
SkDeferredCanvas()81 SkDeferredCanvas::SkDeferredCanvas() {
82     init();
83 }
84 
SkDeferredCanvas(SkDevice * device)85 SkDeferredCanvas::SkDeferredCanvas(SkDevice* device) {
86     init();
87     setDevice(device);
88 }
89 
SkDeferredCanvas(SkDevice * device,DeviceContext * deviceContext)90 SkDeferredCanvas::SkDeferredCanvas(SkDevice* device,
91                                    DeviceContext* deviceContext) {
92     init();
93     setDevice(device);
94     setDeviceContext(deviceContext);
95 }
96 
init()97 void SkDeferredCanvas::init() {
98     fDeferredDrawing = true; // On by default
99 }
100 
validate() const101 void SkDeferredCanvas::validate() const {
102     SkASSERT(getDevice());
103 }
104 
drawingCanvas() const105 SkCanvas* SkDeferredCanvas::drawingCanvas() const {
106     validate();
107     return fDeferredDrawing ? getDeferredDevice()->recordingCanvas() :
108         getDeferredDevice()->immediateCanvas();
109 }
110 
flushIfNeeded(const SkBitmap & bitmap)111 void SkDeferredCanvas::flushIfNeeded(const SkBitmap& bitmap) {
112     validate();
113     if (fDeferredDrawing) {
114         getDeferredDevice()->flushIfNeeded(bitmap);
115     }
116 }
117 
getDeferredDevice() const118 SkDeferredCanvas::DeferredDevice* SkDeferredCanvas::getDeferredDevice() const {
119     return static_cast<SkDeferredCanvas::DeferredDevice*>(getDevice());
120 }
121 
setDeferredDrawing(bool val)122 void SkDeferredCanvas::setDeferredDrawing(bool val) {
123     validate(); // Must set device before calling this method
124     SkASSERT(drawingCanvas()->getSaveCount() == 1);
125     if (val != fDeferredDrawing) {
126         if (fDeferredDrawing) {
127             // Going live.
128             getDeferredDevice()->flushPending();
129         }
130         fDeferredDrawing = val;
131     }
132 }
133 
~SkDeferredCanvas()134 SkDeferredCanvas::~SkDeferredCanvas() {
135 }
136 
setDevice(SkDevice * device)137 SkDevice* SkDeferredCanvas::setDevice(SkDevice* device) {
138     INHERITED::setDevice(SkNEW_ARGS(DeferredDevice, (device)))->unref();
139     return device;
140 }
141 
setDeviceContext(DeviceContext * deviceContext)142 SkDeferredCanvas::DeviceContext* SkDeferredCanvas::setDeviceContext(
143     DeviceContext* deviceContext) {
144 
145     DeferredDevice* deferredDevice = getDeferredDevice();
146     SkASSERT(deferredDevice);
147     if (deferredDevice) {
148         deferredDevice->setDeviceContext(deviceContext);
149     }
150     return deviceContext;
151 }
152 
isFullFrame(const SkRect * rect,const SkPaint * paint) const153 bool SkDeferredCanvas::isFullFrame(const SkRect* rect,
154                                    const SkPaint* paint) const {
155     SkCanvas* canvas = drawingCanvas();
156     SkISize canvasSize = getDeviceSize();
157     if (rect) {
158         if (!canvas->getTotalMatrix().rectStaysRect()) {
159             return false; // conservative
160         }
161 
162         SkRect transformedRect;
163         canvas->getTotalMatrix().mapRect(&transformedRect, *rect);
164 
165         if (paint) {
166             SkPaint::Style paintStyle = paint->getStyle();
167             if (!(paintStyle == SkPaint::kFill_Style ||
168                 paintStyle == SkPaint::kStrokeAndFill_Style)) {
169                 return false;
170             }
171             if (paint->getMaskFilter() || paint->getLooper()
172                 || paint->getPathEffect() || paint->getImageFilter()) {
173                 return false; // conservative
174             }
175         }
176 
177         // The following test holds with AA enabled, and is conservative
178         // by a 0.5 pixel margin with AA disabled
179         if (transformedRect.fLeft > SkIntToScalar(0) ||
180             transformedRect.fTop > SkIntToScalar(0) ||
181             transformedRect.fRight < SkIntToScalar(canvasSize.fWidth) ||
182             transformedRect.fBottom < SkIntToScalar(canvasSize.fHeight)) {
183             return false;
184         }
185     }
186 
187     switch (canvas->getClipType()) {
188         case SkCanvas::kRect_ClipType :
189             {
190                 SkIRect bounds;
191                 canvas->getClipDeviceBounds(&bounds);
192                 if (bounds.fLeft > 0 || bounds.fTop > 0 ||
193                     bounds.fRight < canvasSize.fWidth ||
194                     bounds.fBottom < canvasSize.fHeight)
195                     return false;
196             }
197             break;
198         case SkCanvas::kComplex_ClipType :
199             return false; // conservative
200         case SkCanvas::kEmpty_ClipType:
201         default:
202             break;
203     };
204 
205     return true;
206 }
207 
save(SaveFlags flags)208 int SkDeferredCanvas::save(SaveFlags flags) {
209     drawingCanvas()->save(flags);
210     return this->INHERITED::save(flags);
211 }
212 
saveLayer(const SkRect * bounds,const SkPaint * paint,SaveFlags flags)213 int SkDeferredCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
214                                 SaveFlags flags) {
215     drawingCanvas()->saveLayer(bounds, paint, flags);
216     int count = this->INHERITED::save(flags);
217     this->clipRectBounds(bounds, flags, NULL);
218     return count;
219 }
220 
restore()221 void SkDeferredCanvas::restore() {
222     drawingCanvas()->restore();
223     this->INHERITED::restore();
224 }
225 
isDrawingToLayer() const226 bool SkDeferredCanvas::isDrawingToLayer() const {
227     return drawingCanvas()->isDrawingToLayer();
228 }
229 
translate(SkScalar dx,SkScalar dy)230 bool SkDeferredCanvas::translate(SkScalar dx, SkScalar dy) {
231     drawingCanvas()->translate(dx, dy);
232     return this->INHERITED::translate(dx, dy);
233 }
234 
scale(SkScalar sx,SkScalar sy)235 bool SkDeferredCanvas::scale(SkScalar sx, SkScalar sy) {
236     drawingCanvas()->scale(sx, sy);
237     return this->INHERITED::scale(sx, sy);
238 }
239 
rotate(SkScalar degrees)240 bool SkDeferredCanvas::rotate(SkScalar degrees) {
241     drawingCanvas()->rotate(degrees);
242     return this->INHERITED::rotate(degrees);
243 }
244 
skew(SkScalar sx,SkScalar sy)245 bool SkDeferredCanvas::skew(SkScalar sx, SkScalar sy) {
246     drawingCanvas()->skew(sx, sy);
247     return this->INHERITED::skew(sx, sy);
248 }
249 
concat(const SkMatrix & matrix)250 bool SkDeferredCanvas::concat(const SkMatrix& matrix) {
251     drawingCanvas()->concat(matrix);
252     return this->INHERITED::concat(matrix);
253 }
254 
setMatrix(const SkMatrix & matrix)255 void SkDeferredCanvas::setMatrix(const SkMatrix& matrix) {
256     drawingCanvas()->setMatrix(matrix);
257     this->INHERITED::setMatrix(matrix);
258 }
259 
clipRect(const SkRect & rect,SkRegion::Op op,bool doAntiAlias)260 bool SkDeferredCanvas::clipRect(const SkRect& rect,
261                                 SkRegion::Op op,
262                                 bool doAntiAlias) {
263     drawingCanvas()->clipRect(rect, op, doAntiAlias);
264     return this->INHERITED::clipRect(rect, op, doAntiAlias);
265 }
266 
clipPath(const SkPath & path,SkRegion::Op op,bool doAntiAlias)267 bool SkDeferredCanvas::clipPath(const SkPath& path,
268                                 SkRegion::Op op,
269                                 bool doAntiAlias) {
270     drawingCanvas()->clipPath(path, op, doAntiAlias);
271     return this->INHERITED::clipPath(path, op, doAntiAlias);
272 }
273 
clipRegion(const SkRegion & deviceRgn,SkRegion::Op op)274 bool SkDeferredCanvas::clipRegion(const SkRegion& deviceRgn,
275                                   SkRegion::Op op) {
276     drawingCanvas()->clipRegion(deviceRgn, op);
277     return this->INHERITED::clipRegion(deviceRgn, op);
278 }
279 
clear(SkColor color)280 void SkDeferredCanvas::clear(SkColor color) {
281     // purge pending commands
282     if (fDeferredDrawing) {
283         getDeferredDevice()->contentsCleared();
284     }
285 
286     drawingCanvas()->clear(color);
287 }
288 
drawPaint(const SkPaint & paint)289 void SkDeferredCanvas::drawPaint(const SkPaint& paint) {
290     if (fDeferredDrawing && isFullFrame(NULL, &paint) &&
291         isPaintOpaque(&paint)) {
292         getDeferredDevice()->contentsCleared();
293     }
294 
295     drawingCanvas()->drawPaint(paint);
296 }
297 
drawPoints(PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)298 void SkDeferredCanvas::drawPoints(PointMode mode, size_t count,
299                                   const SkPoint pts[], const SkPaint& paint) {
300     drawingCanvas()->drawPoints(mode, count, pts, paint);
301 }
302 
drawRect(const SkRect & rect,const SkPaint & paint)303 void SkDeferredCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
304     if (fDeferredDrawing && isFullFrame(&rect, &paint) &&
305         isPaintOpaque(&paint)) {
306         getDeferredDevice()->contentsCleared();
307     }
308 
309     drawingCanvas()->drawRect(rect, paint);
310 }
311 
drawPath(const SkPath & path,const SkPaint & paint)312 void SkDeferredCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
313     drawingCanvas()->drawPath(path, paint);
314 }
315 
drawBitmap(const SkBitmap & bitmap,SkScalar left,SkScalar top,const SkPaint * paint)316 void SkDeferredCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left,
317                                   SkScalar top, const SkPaint* paint) {
318     SkRect bitmapRect = SkRect::MakeXYWH(left, top,
319         SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height()));
320     if (fDeferredDrawing &&
321         isFullFrame(&bitmapRect, paint) &&
322         isPaintOpaque(paint, &bitmap)) {
323         getDeferredDevice()->contentsCleared();
324     }
325 
326     drawingCanvas()->drawBitmap(bitmap, left, top, paint);
327     flushIfNeeded(bitmap);
328 }
329 
drawBitmapRect(const SkBitmap & bitmap,const SkIRect * src,const SkRect & dst,const SkPaint * paint)330 void SkDeferredCanvas::drawBitmapRect(const SkBitmap& bitmap,
331                                       const SkIRect* src,
332                                       const SkRect& dst,
333                                       const SkPaint* paint) {
334     if (fDeferredDrawing &&
335         isFullFrame(&dst, paint) &&
336         isPaintOpaque(paint, &bitmap)) {
337         getDeferredDevice()->contentsCleared();
338     }
339 
340     drawingCanvas()->drawBitmapRect(bitmap, src,
341                                     dst, paint);
342     flushIfNeeded(bitmap);
343 }
344 
345 
drawBitmapMatrix(const SkBitmap & bitmap,const SkMatrix & m,const SkPaint * paint)346 void SkDeferredCanvas::drawBitmapMatrix(const SkBitmap& bitmap,
347                                         const SkMatrix& m,
348                                         const SkPaint* paint) {
349     // TODO: reset recording canvas if paint+bitmap is opaque and clip rect
350     // covers canvas entirely and transformed bitmap covers canvas entirely
351     drawingCanvas()->drawBitmapMatrix(bitmap, m, paint);
352     flushIfNeeded(bitmap);
353 }
354 
drawBitmapNine(const SkBitmap & bitmap,const SkIRect & center,const SkRect & dst,const SkPaint * paint)355 void SkDeferredCanvas::drawBitmapNine(const SkBitmap& bitmap,
356                                       const SkIRect& center, const SkRect& dst,
357                                       const SkPaint* paint) {
358     // TODO: reset recording canvas if paint+bitmap is opaque and clip rect
359     // covers canvas entirely and dst covers canvas entirely
360     drawingCanvas()->drawBitmapNine(bitmap, center,
361                                     dst, paint);
362     flushIfNeeded(bitmap);
363 }
364 
drawSprite(const SkBitmap & bitmap,int left,int top,const SkPaint * paint)365 void SkDeferredCanvas::drawSprite(const SkBitmap& bitmap, int left, int top,
366                                   const SkPaint* paint) {
367     SkRect bitmapRect = SkRect::MakeXYWH(
368         SkIntToScalar(left),
369         SkIntToScalar(top),
370         SkIntToScalar(bitmap.width()),
371         SkIntToScalar(bitmap.height()));
372     if (fDeferredDrawing &&
373         isFullFrame(&bitmapRect, paint) &&
374         isPaintOpaque(paint, &bitmap)) {
375         getDeferredDevice()->contentsCleared();
376     }
377 
378     drawingCanvas()->drawSprite(bitmap, left, top,
379                                 paint);
380     flushIfNeeded(bitmap);
381 }
382 
drawText(const void * text,size_t byteLength,SkScalar x,SkScalar y,const SkPaint & paint)383 void SkDeferredCanvas::drawText(const void* text, size_t byteLength,
384                                 SkScalar x, SkScalar y, const SkPaint& paint) {
385     drawingCanvas()->drawText(text, byteLength, x, y, paint);
386 }
387 
drawPosText(const void * text,size_t byteLength,const SkPoint pos[],const SkPaint & paint)388 void SkDeferredCanvas::drawPosText(const void* text, size_t byteLength,
389                                    const SkPoint pos[], const SkPaint& paint) {
390     drawingCanvas()->drawPosText(text, byteLength, pos, paint);
391 }
392 
drawPosTextH(const void * text,size_t byteLength,const SkScalar xpos[],SkScalar constY,const SkPaint & paint)393 void SkDeferredCanvas::drawPosTextH(const void* text, size_t byteLength,
394                                     const SkScalar xpos[], SkScalar constY,
395                                     const SkPaint& paint) {
396     drawingCanvas()->drawPosTextH(text, byteLength, xpos, constY, paint);
397 }
398 
drawTextOnPath(const void * text,size_t byteLength,const SkPath & path,const SkMatrix * matrix,const SkPaint & paint)399 void SkDeferredCanvas::drawTextOnPath(const void* text, size_t byteLength,
400                                       const SkPath& path,
401                                       const SkMatrix* matrix,
402                                       const SkPaint& paint) {
403     drawingCanvas()->drawTextOnPath(text, byteLength,
404                                     path, matrix,
405                                     paint);
406 }
407 
drawPicture(SkPicture & picture)408 void SkDeferredCanvas::drawPicture(SkPicture& picture) {
409     drawingCanvas()->drawPicture(picture);
410 }
411 
drawVertices(VertexMode vmode,int vertexCount,const SkPoint vertices[],const SkPoint texs[],const SkColor colors[],SkXfermode * xmode,const uint16_t indices[],int indexCount,const SkPaint & paint)412 void SkDeferredCanvas::drawVertices(VertexMode vmode, int vertexCount,
413                                     const SkPoint vertices[],
414                                     const SkPoint texs[],
415                                     const SkColor colors[], SkXfermode* xmode,
416                                     const uint16_t indices[], int indexCount,
417                                     const SkPaint& paint) {
418     drawingCanvas()->drawVertices(vmode, vertexCount,
419                                   vertices, texs,
420                                   colors, xmode,
421                                   indices, indexCount,
422                                   paint);
423 }
424 
setBounder(SkBounder * bounder)425 SkBounder* SkDeferredCanvas::setBounder(SkBounder* bounder) {
426     drawingCanvas()->setBounder(bounder);
427     return INHERITED::setBounder(bounder);
428 }
429 
setDrawFilter(SkDrawFilter * filter)430 SkDrawFilter* SkDeferredCanvas::setDrawFilter(SkDrawFilter* filter) {
431     drawingCanvas()->setDrawFilter(filter);
432     return INHERITED::setDrawFilter(filter);
433 }
434 
canvasForDrawIter()435 SkCanvas* SkDeferredCanvas::canvasForDrawIter() {
436     return drawingCanvas();
437 }
438 
439 // SkDeferredCanvas::DeferredDevice
440 //------------------------------------
441 
DeferredDevice(SkDevice * immediateDevice,DeviceContext * deviceContext)442 SkDeferredCanvas::DeferredDevice::DeferredDevice(
443     SkDevice* immediateDevice, DeviceContext* deviceContext) :
444     SkDevice(SkBitmap::kNo_Config, immediateDevice->width(),
445              immediateDevice->height(), immediateDevice->isOpaque())
446     , fFreshFrame(true) {
447 
448     fDeviceContext = deviceContext;
449     SkSafeRef(fDeviceContext);
450     fImmediateDevice = immediateDevice; // ref counted via fImmediateCanvas
451     fImmediateCanvas = SkNEW_ARGS(SkCanvas, (fImmediateDevice));
452     fRecordingCanvas = fPicture.beginRecording(fImmediateDevice->width(),
453         fImmediateDevice->height(), 0);
454 }
455 
~DeferredDevice()456 SkDeferredCanvas::DeferredDevice::~DeferredDevice() {
457     SkSafeUnref(fImmediateCanvas);
458     SkSafeUnref(fDeviceContext);
459 }
460 
setDeviceContext(DeviceContext * deviceContext)461 void SkDeferredCanvas::DeferredDevice::setDeviceContext(
462     DeviceContext* deviceContext) {
463     SkRefCnt_SafeAssign(fDeviceContext, deviceContext);
464 }
465 
contentsCleared()466 void SkDeferredCanvas::DeferredDevice::contentsCleared() {
467     if (!fRecordingCanvas->isDrawingToLayer()) {
468         fFreshFrame = true;
469 
470         // TODO: find a way to transfer the state stack and layers
471         // to the new recording canvas.  For now, purging only works
472         // with an empty stack.
473         if (fRecordingCanvas->getSaveCount() == 0) {
474 
475             // Save state that is trashed by the purge
476             SkDrawFilter* drawFilter = fRecordingCanvas->getDrawFilter();
477             SkSafeRef(drawFilter); // So that it survives the purge
478             SkMatrix matrix = fRecordingCanvas->getTotalMatrix();
479             SkRegion clipRegion = fRecordingCanvas->getTotalClip();
480 
481             // beginRecording creates a new recording canvas and discards the
482             // old one, hence purging deferred draw ops.
483             fRecordingCanvas = fPicture.beginRecording(
484                 fImmediateDevice->width(),
485                 fImmediateDevice->height(), 0);
486 
487             // Restore pre-purge state
488             if (!clipRegion.isEmpty()) {
489                 fRecordingCanvas->clipRegion(clipRegion,
490                     SkRegion::kReplace_Op);
491             }
492             if (!matrix.isIdentity()) {
493                 fRecordingCanvas->setMatrix(matrix);
494             }
495             if (drawFilter) {
496                 fRecordingCanvas->setDrawFilter(drawFilter)->unref();
497             }
498         }
499     }
500 }
501 
isFreshFrame()502 bool SkDeferredCanvas::DeferredDevice::isFreshFrame() {
503     bool ret = fFreshFrame;
504     fFreshFrame = false;
505     return ret;
506 }
507 
flushPending()508 void SkDeferredCanvas::DeferredDevice::flushPending() {
509     if (fDeviceContext) {
510         fDeviceContext->prepareForDraw();
511     }
512     fPicture.draw(fImmediateCanvas);
513     fRecordingCanvas = fPicture.beginRecording(fImmediateDevice->width(),
514         fImmediateDevice->height(), 0);
515 }
516 
flush()517 void SkDeferredCanvas::DeferredDevice::flush() {
518     flushPending();
519     fImmediateCanvas->flush();
520 }
521 
flushIfNeeded(const SkBitmap & bitmap)522 void SkDeferredCanvas::DeferredDevice::flushIfNeeded(const SkBitmap& bitmap) {
523     if (bitmap.isImmutable()) {
524         return; // safe to deffer without registering a dependency
525     }
526 
527     // For now, drawing a writable bitmap triggers a flush
528     // TODO: implement read-only semantics and auto buffer duplication on write
529     // in SkBitmap/SkPixelRef, which will make deferral possible in this case.
530     flushPending();
531 }
532 
getDeviceCapabilities()533 uint32_t SkDeferredCanvas::DeferredDevice::getDeviceCapabilities() {
534     return fImmediateDevice->getDeviceCapabilities();
535 }
536 
width() const537 int SkDeferredCanvas::DeferredDevice::width() const {
538     return fImmediateDevice->width();
539 }
540 
height() const541 int SkDeferredCanvas::DeferredDevice::height() const {
542     return fImmediateDevice->height();
543 }
544 
accessRenderTarget()545 SkGpuRenderTarget* SkDeferredCanvas::DeferredDevice::accessRenderTarget() {
546     flushPending();
547     return fImmediateDevice->accessRenderTarget();
548 }
549 
writePixels(const SkBitmap & bitmap,int x,int y,SkCanvas::Config8888 config8888)550 void SkDeferredCanvas::DeferredDevice::writePixels(const SkBitmap& bitmap,
551     int x, int y, SkCanvas::Config8888 config8888) {
552 
553     if (x <= 0 && y <= 0 && (x + bitmap.width()) >= width() &&
554         (y + bitmap.height()) >= height()) {
555         contentsCleared();
556     }
557 
558     if (SkBitmap::kARGB_8888_Config == bitmap.config() &&
559         SkCanvas::kNative_Premul_Config8888 != config8888 &&
560         kPMColorAlias != config8888) {
561         //Special case config: no deferral
562         flushPending();
563         fImmediateDevice->writePixels(bitmap, x, y, config8888);
564     }
565 
566     SkPaint paint;
567     paint.setXfermodeMode(SkXfermode::kSrc_Mode);
568     fRecordingCanvas->drawSprite(bitmap, x, y, &paint);
569     flushIfNeeded(bitmap);
570 }
571 
onAccessBitmap(SkBitmap *)572 const SkBitmap& SkDeferredCanvas::DeferredDevice::onAccessBitmap(SkBitmap*) {
573     flushPending();
574     return fImmediateDevice->accessBitmap(false);
575 }
576 
onCreateCompatibleDevice(SkBitmap::Config config,int width,int height,bool isOpaque,Usage usage)577 SkDevice* SkDeferredCanvas::DeferredDevice::onCreateCompatibleDevice(
578     SkBitmap::Config config, int width, int height, bool isOpaque,
579     Usage usage) {
580 
581     // Save layer usage not supported, and not required by SkDeferredCanvas.
582     SkASSERT(usage != kSaveLayer_Usage);
583     // Create a compatible non-deferred device.
584     SkDevice* compatibleDevice =
585         fImmediateDevice->createCompatibleDevice(config, width, height,
586             isOpaque);
587     return SkNEW_ARGS(DeferredDevice, (compatibleDevice, fDeviceContext));
588 }
589 
onReadPixels(const SkBitmap & bitmap,int x,int y,SkCanvas::Config8888 config8888)590 bool SkDeferredCanvas::DeferredDevice::onReadPixels(
591     const SkBitmap& bitmap, int x, int y, SkCanvas::Config8888 config8888) {
592     flushPending();
593     return fImmediateCanvas->readPixels(const_cast<SkBitmap*>(&bitmap),
594                                                    x, y, config8888);
595 }
596