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