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