blob: 731e80b2cef8337c9336b70f8588e87a159fb860 [file] [log] [blame]
junov@google.com4370aed2012-01-18 16:21:08 +00001
2/*
junov@chromium.org10f7f972012-07-31 21:01:51 +00003 * Copyright 2012 Google Inc.
junov@google.com4370aed2012-01-18 16:21:08 +00004 *
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
reed@google.com563a3b42012-06-26 19:24:50 +000016SK_DEFINE_INST_COUNT(SkDeferredCanvas::DeviceContext)
17
junov@chromium.orgbfeddae2012-07-23 13:35:14 +000018enum {
19 // Deferred canvas will auto-flush when recording reaches this limit
20 kDefaultMaxRecordingStorageBytes = 64*1024*1024,
21};
22
junov@google.com4370aed2012-01-18 16:21:08 +000023namespace {
junov@chromium.org10f7f972012-07-31 21:01:51 +000024bool shouldDrawImmediately(const SkBitmap* bitmap, const SkPaint* paint) {
25 if (bitmap && bitmap->getTexture() && !bitmap->isImmutable()) {
26 return true;
27 }
28 if (paint) {
29 SkShader* shader = paint->getShader();
30 // Here we detect the case where the shader is an SkBitmapProcShader
31 // with a gpu texture attached. Checking this without RTTI
32 // requires making the assumption that only gradient shaders
33 // and SkBitmapProcShader implement asABitmap(). The following
34 // code may need to be revised if that assumption is ever broken.
35 if (shader && !shader->asAGradient(NULL)) {
36 SkBitmap bm;
37 if (shader->asABitmap(&bm, NULL, NULL) &&
38 NULL != bm.getTexture()) {
39 return true;
40 }
41 }
42 }
43 return false;
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +000044}
45}
46
47class AutoImmediateDrawIfNeeded {
48public:
junov@chromium.org10f7f972012-07-31 21:01:51 +000049 AutoImmediateDrawIfNeeded(SkDeferredCanvas& canvas, const SkBitmap* bitmap,
50 const SkPaint* paint) {
51 this->init(canvas, bitmap, paint);
52 }
53
54 AutoImmediateDrawIfNeeded(SkDeferredCanvas& canvas, const SkPaint* paint) {
55 this->init(canvas, NULL, paint);
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +000056 }
57
58 ~AutoImmediateDrawIfNeeded() {
59 if (fCanvas) {
60 fCanvas->setDeferredDrawing(true);
61 }
62 }
63private:
junov@chromium.org10f7f972012-07-31 21:01:51 +000064 void init(SkDeferredCanvas& canvas, const SkBitmap* bitmap, const SkPaint* paint)
65 {
66 if (canvas.isDeferredDrawing() && shouldDrawImmediately(bitmap, paint)) {
67 canvas.setDeferredDrawing(false);
68 fCanvas = &canvas;
69 } else {
70 fCanvas = NULL;
71 }
72 }
73
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +000074 SkDeferredCanvas* fCanvas;
75};
76
77namespace {
junov@google.com4370aed2012-01-18 16:21:08 +000078
junov@chromium.orgc16ca922012-02-24 22:06:27 +000079bool isPaintOpaque(const SkPaint* paint,
80 const SkBitmap* bmpReplacesShader = NULL) {
junov@google.com4370aed2012-01-18 16:21:08 +000081 // TODO: SkXfermode should have a virtual isOpaque method, which would
82 // make it possible to test modes that do not have a Coeff representation.
junov@chromium.org87f982c2012-02-23 21:34:34 +000083
84 if (!paint) {
85 return bmpReplacesShader ? bmpReplacesShader->isOpaque() : true;
86 }
87
junov@google.com4370aed2012-01-18 16:21:08 +000088 SkXfermode::Coeff srcCoeff, dstCoeff;
junov@chromium.org87f982c2012-02-23 21:34:34 +000089 if (SkXfermode::AsCoeff(paint->getXfermode(), &srcCoeff, &dstCoeff)){
junov@google.com4370aed2012-01-18 16:21:08 +000090 switch (dstCoeff) {
91 case SkXfermode::kZero_Coeff:
92 return true;
93 case SkXfermode::kISA_Coeff:
junov@chromium.org87f982c2012-02-23 21:34:34 +000094 if (paint->getAlpha() != 255) {
junov@google.com4370aed2012-01-18 16:21:08 +000095 break;
96 }
97 if (bmpReplacesShader) {
98 if (!bmpReplacesShader->isOpaque()) {
99 break;
100 }
junov@chromium.org87f982c2012-02-23 21:34:34 +0000101 } else if (paint->getShader() && !paint->getShader()->isOpaque()) {
junov@google.com4370aed2012-01-18 16:21:08 +0000102 break;
103 }
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000104 if (paint->getColorFilter() &&
105 ((paint->getColorFilter()->getFlags() &
junov@google.com4370aed2012-01-18 16:21:08 +0000106 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
107 break;
108 }
109 return true;
110 case SkXfermode::kSA_Coeff:
junov@chromium.org87f982c2012-02-23 21:34:34 +0000111 if (paint->getAlpha() != 0) {
junov@google.com4370aed2012-01-18 16:21:08 +0000112 break;
113 }
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000114 if (paint->getColorFilter() &&
115 ((paint->getColorFilter()->getFlags() &
junov@google.com4370aed2012-01-18 16:21:08 +0000116 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
117 break;
118 }
119 return true;
120 case SkXfermode::kSC_Coeff:
junov@chromium.org87f982c2012-02-23 21:34:34 +0000121 if (paint->getColor() != 0) { // all components must be 0
junov@google.com4370aed2012-01-18 16:21:08 +0000122 break;
123 }
junov@chromium.org87f982c2012-02-23 21:34:34 +0000124 if (bmpReplacesShader || paint->getShader()) {
junov@google.com4370aed2012-01-18 16:21:08 +0000125 break;
126 }
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000127 if (paint->getColorFilter() && (
128 (paint->getColorFilter()->getFlags() &
junov@google.com4370aed2012-01-18 16:21:08 +0000129 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
130 break;
131 }
132 return true;
133 default:
134 break;
135 }
136 }
137 return false;
138}
139
140} // unnamed namespace
141
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000142SkDeferredCanvas::SkDeferredCanvas() {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000143 this->init();
junov@google.com4370aed2012-01-18 16:21:08 +0000144}
145
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000146SkDeferredCanvas::SkDeferredCanvas(SkDevice* device) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000147 this->init();
148 this->setDevice(device);
junov@google.com4370aed2012-01-18 16:21:08 +0000149}
150
151SkDeferredCanvas::SkDeferredCanvas(SkDevice* device,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000152 DeviceContext* deviceContext) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000153 this->init();
154 this->setDevice(device);
155 this->setDeviceContext(deviceContext);
junov@google.com4370aed2012-01-18 16:21:08 +0000156}
157
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000158void SkDeferredCanvas::init() {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000159 fDeferredDrawing = true; // On by default
junov@google.com4370aed2012-01-18 16:21:08 +0000160}
161
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000162void SkDeferredCanvas::setMaxRecordingStorage(size_t maxStorage) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000163 this->validate();
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000164 this->getDeferredDevice()->setMaxRecordingStorage(maxStorage);
165}
166
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000167size_t SkDeferredCanvas::storageAllocatedForRecording() const {
168 return this->getDeferredDevice()->storageAllocatedForRecording();
169}
170
171size_t SkDeferredCanvas::freeMemoryIfPossible(size_t bytesToFree) {
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000172 return this->getDeferredDevice()->freeMemoryIfPossible(bytesToFree);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000173}
174
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000175void SkDeferredCanvas::validate() const {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000176 SkASSERT(this->getDevice());
junov@google.com4370aed2012-01-18 16:21:08 +0000177}
178
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000179SkCanvas* SkDeferredCanvas::drawingCanvas() const {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000180 this->validate();
181 return fDeferredDrawing ? this->getDeferredDevice()->recordingCanvas() :
182 this->getDeferredDevice()->immediateCanvas();
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000183}
184
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000185SkDeferredCanvas::DeferredDevice* SkDeferredCanvas::getDeferredDevice() const {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000186 return static_cast<SkDeferredCanvas::DeferredDevice*>(this->getDevice());
junov@google.com4370aed2012-01-18 16:21:08 +0000187}
188
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000189void SkDeferredCanvas::setDeferredDrawing(bool val) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000190 this->validate(); // Must set device before calling this method
junov@google.com4370aed2012-01-18 16:21:08 +0000191 if (val != fDeferredDrawing) {
192 if (fDeferredDrawing) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000193 // Going live.
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000194 this->getDeferredDevice()->flushPending();
junov@google.com4370aed2012-01-18 16:21:08 +0000195 }
196 fDeferredDrawing = val;
197 }
198}
199
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +0000200bool SkDeferredCanvas::isDeferredDrawing() {
201 return fDeferredDrawing;
202}
203
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000204SkDeferredCanvas::~SkDeferredCanvas() {
junov@google.com4370aed2012-01-18 16:21:08 +0000205}
206
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000207SkDevice* SkDeferredCanvas::setDevice(SkDevice* device) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000208 this->INHERITED::setDevice(SkNEW_ARGS(DeferredDevice, (device)))->unref();
junov@google.com4370aed2012-01-18 16:21:08 +0000209 return device;
210}
211
212SkDeferredCanvas::DeviceContext* SkDeferredCanvas::setDeviceContext(
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000213 DeviceContext* deviceContext) {
214
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000215 DeferredDevice* deferredDevice = this->getDeferredDevice();
junov@google.com4370aed2012-01-18 16:21:08 +0000216 SkASSERT(deferredDevice);
217 if (deferredDevice) {
218 deferredDevice->setDeviceContext(deviceContext);
219 }
220 return deviceContext;
221}
222
223bool SkDeferredCanvas::isFullFrame(const SkRect* rect,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000224 const SkPaint* paint) const {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000225 SkCanvas* canvas = this->drawingCanvas();
226 SkISize canvasSize = this->getDeviceSize();
junov@google.com4370aed2012-01-18 16:21:08 +0000227 if (rect) {
228 if (!canvas->getTotalMatrix().rectStaysRect()) {
229 return false; // conservative
230 }
231
232 SkRect transformedRect;
233 canvas->getTotalMatrix().mapRect(&transformedRect, *rect);
234
235 if (paint) {
236 SkPaint::Style paintStyle = paint->getStyle();
237 if (!(paintStyle == SkPaint::kFill_Style ||
238 paintStyle == SkPaint::kStrokeAndFill_Style)) {
239 return false;
240 }
241 if (paint->getMaskFilter() || paint->getLooper()
242 || paint->getPathEffect() || paint->getImageFilter()) {
243 return false; // conservative
244 }
245 }
246
247 // The following test holds with AA enabled, and is conservative
248 // by a 0.5 pixel margin with AA disabled
junov@chromium.orgb1e218e2012-02-13 22:27:58 +0000249 if (transformedRect.fLeft > SkIntToScalar(0) ||
250 transformedRect.fTop > SkIntToScalar(0) ||
251 transformedRect.fRight < SkIntToScalar(canvasSize.fWidth) ||
252 transformedRect.fBottom < SkIntToScalar(canvasSize.fHeight)) {
junov@google.com4370aed2012-01-18 16:21:08 +0000253 return false;
254 }
255 }
256
257 switch (canvas->getClipType()) {
258 case SkCanvas::kRect_ClipType :
259 {
260 SkIRect bounds;
261 canvas->getClipDeviceBounds(&bounds);
262 if (bounds.fLeft > 0 || bounds.fTop > 0 ||
263 bounds.fRight < canvasSize.fWidth ||
264 bounds.fBottom < canvasSize.fHeight)
265 return false;
266 }
267 break;
268 case SkCanvas::kComplex_ClipType :
269 return false; // conservative
270 case SkCanvas::kEmpty_ClipType:
271 default:
272 break;
273 };
274
275 return true;
276}
277
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000278int SkDeferredCanvas::save(SaveFlags flags) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000279 this->drawingCanvas()->save(flags);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000280 return this->INHERITED::save(flags);
junov@google.com4370aed2012-01-18 16:21:08 +0000281}
282
283int SkDeferredCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000284 SaveFlags flags) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000285 this->drawingCanvas()->saveLayer(bounds, paint, flags);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000286 int count = this->INHERITED::save(flags);
287 this->clipRectBounds(bounds, flags, NULL);
288 return count;
junov@google.com4370aed2012-01-18 16:21:08 +0000289}
290
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000291void SkDeferredCanvas::restore() {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000292 this->drawingCanvas()->restore();
junov@chromium.orga907ac32012-02-24 21:54:07 +0000293 this->INHERITED::restore();
junov@google.com4370aed2012-01-18 16:21:08 +0000294}
295
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000296bool SkDeferredCanvas::isDrawingToLayer() const {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000297 return this->drawingCanvas()->isDrawingToLayer();
junov@google.com4370aed2012-01-18 16:21:08 +0000298}
299
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000300bool SkDeferredCanvas::translate(SkScalar dx, SkScalar dy) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000301 this->drawingCanvas()->translate(dx, dy);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000302 return this->INHERITED::translate(dx, dy);
junov@google.com4370aed2012-01-18 16:21:08 +0000303}
304
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000305bool SkDeferredCanvas::scale(SkScalar sx, SkScalar sy) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000306 this->drawingCanvas()->scale(sx, sy);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000307 return this->INHERITED::scale(sx, sy);
junov@google.com4370aed2012-01-18 16:21:08 +0000308}
309
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000310bool SkDeferredCanvas::rotate(SkScalar degrees) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000311 this->drawingCanvas()->rotate(degrees);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000312 return this->INHERITED::rotate(degrees);
junov@google.com4370aed2012-01-18 16:21:08 +0000313}
314
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000315bool SkDeferredCanvas::skew(SkScalar sx, SkScalar sy) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000316 this->drawingCanvas()->skew(sx, sy);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000317 return this->INHERITED::skew(sx, sy);
junov@google.com4370aed2012-01-18 16:21:08 +0000318}
319
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000320bool SkDeferredCanvas::concat(const SkMatrix& matrix) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000321 this->drawingCanvas()->concat(matrix);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000322 return this->INHERITED::concat(matrix);
junov@google.com4370aed2012-01-18 16:21:08 +0000323}
324
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000325void SkDeferredCanvas::setMatrix(const SkMatrix& matrix) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000326 this->drawingCanvas()->setMatrix(matrix);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000327 this->INHERITED::setMatrix(matrix);
junov@google.com4370aed2012-01-18 16:21:08 +0000328}
329
330bool SkDeferredCanvas::clipRect(const SkRect& rect,
331 SkRegion::Op op,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000332 bool doAntiAlias) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000333 this->drawingCanvas()->clipRect(rect, op, doAntiAlias);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000334 return this->INHERITED::clipRect(rect, op, doAntiAlias);
junov@google.com4370aed2012-01-18 16:21:08 +0000335}
336
337bool SkDeferredCanvas::clipPath(const SkPath& path,
338 SkRegion::Op op,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000339 bool doAntiAlias) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000340 this->drawingCanvas()->clipPath(path, op, doAntiAlias);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000341 return this->INHERITED::clipPath(path, op, doAntiAlias);
junov@google.com4370aed2012-01-18 16:21:08 +0000342}
343
344bool SkDeferredCanvas::clipRegion(const SkRegion& deviceRgn,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000345 SkRegion::Op op) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000346 this->drawingCanvas()->clipRegion(deviceRgn, op);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000347 return this->INHERITED::clipRegion(deviceRgn, op);
junov@google.com4370aed2012-01-18 16:21:08 +0000348}
349
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000350void SkDeferredCanvas::clear(SkColor color) {
junov@google.com4370aed2012-01-18 16:21:08 +0000351 // purge pending commands
352 if (fDeferredDrawing) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000353 this->getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000354 }
355
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000356 this->drawingCanvas()->clear(color);
junov@google.com4370aed2012-01-18 16:21:08 +0000357}
358
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000359void SkDeferredCanvas::drawPaint(const SkPaint& paint) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000360 if (fDeferredDrawing && this->isFullFrame(NULL, &paint) &&
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000361 isPaintOpaque(&paint)) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000362 this->getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000363 }
junov@chromium.org10f7f972012-07-31 21:01:51 +0000364 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000365 this->drawingCanvas()->drawPaint(paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000366}
367
368void SkDeferredCanvas::drawPoints(PointMode mode, size_t count,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000369 const SkPoint pts[], const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000370 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000371 this->drawingCanvas()->drawPoints(mode, count, pts, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000372}
373
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000374void SkDeferredCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000375 if (fDeferredDrawing && this->isFullFrame(&rect, &paint) &&
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000376 isPaintOpaque(&paint)) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000377 this->getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000378 }
379
junov@chromium.org10f7f972012-07-31 21:01:51 +0000380 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000381 this->drawingCanvas()->drawRect(rect, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000382}
383
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000384void SkDeferredCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000385 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000386 this->drawingCanvas()->drawPath(path, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000387}
388
389void SkDeferredCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000390 SkScalar top, const SkPaint* paint) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000391 SkRect bitmapRect = SkRect::MakeXYWH(left, top,
392 SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height()));
junov@google.com4370aed2012-01-18 16:21:08 +0000393 if (fDeferredDrawing &&
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000394 this->isFullFrame(&bitmapRect, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000395 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000396 this->getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000397 }
398
junov@chromium.org10f7f972012-07-31 21:01:51 +0000399 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000400 this->drawingCanvas()->drawBitmap(bitmap, left, top, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000401}
402
403void SkDeferredCanvas::drawBitmapRect(const SkBitmap& bitmap,
404 const SkIRect* src,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000405 const SkRect& dst,
406 const SkPaint* paint) {
junov@google.com4370aed2012-01-18 16:21:08 +0000407 if (fDeferredDrawing &&
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000408 this->isFullFrame(&dst, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000409 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000410 this->getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000411 }
412
junov@chromium.org10f7f972012-07-31 21:01:51 +0000413 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000414 this->drawingCanvas()->drawBitmapRect(bitmap, src, dst, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000415}
416
417
418void SkDeferredCanvas::drawBitmapMatrix(const SkBitmap& bitmap,
419 const SkMatrix& m,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000420 const SkPaint* paint) {
junov@google.com4370aed2012-01-18 16:21:08 +0000421 // TODO: reset recording canvas if paint+bitmap is opaque and clip rect
422 // covers canvas entirely and transformed bitmap covers canvas entirely
junov@chromium.org10f7f972012-07-31 21:01:51 +0000423 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000424 this->drawingCanvas()->drawBitmapMatrix(bitmap, m, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000425}
426
427void SkDeferredCanvas::drawBitmapNine(const SkBitmap& bitmap,
428 const SkIRect& center, const SkRect& dst,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000429 const SkPaint* paint) {
junov@google.com4370aed2012-01-18 16:21:08 +0000430 // TODO: reset recording canvas if paint+bitmap is opaque and clip rect
431 // covers canvas entirely and dst covers canvas entirely
junov@chromium.org10f7f972012-07-31 21:01:51 +0000432 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000433 this->drawingCanvas()->drawBitmapNine(bitmap, center, dst, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000434}
435
436void SkDeferredCanvas::drawSprite(const SkBitmap& bitmap, int left, int top,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000437 const SkPaint* paint) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000438 SkRect bitmapRect = SkRect::MakeXYWH(
439 SkIntToScalar(left),
440 SkIntToScalar(top),
441 SkIntToScalar(bitmap.width()),
442 SkIntToScalar(bitmap.height()));
junov@google.com4370aed2012-01-18 16:21:08 +0000443 if (fDeferredDrawing &&
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000444 this->isFullFrame(&bitmapRect, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000445 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000446 this->getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000447 }
448
junov@chromium.org10f7f972012-07-31 21:01:51 +0000449 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000450 this->drawingCanvas()->drawSprite(bitmap, left, top, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000451}
452
453void SkDeferredCanvas::drawText(const void* text, size_t byteLength,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000454 SkScalar x, SkScalar y, const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000455 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000456 this->drawingCanvas()->drawText(text, byteLength, x, y, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000457}
458
459void SkDeferredCanvas::drawPosText(const void* text, size_t byteLength,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000460 const SkPoint pos[], const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000461 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000462 this->drawingCanvas()->drawPosText(text, byteLength, pos, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000463}
464
465void SkDeferredCanvas::drawPosTextH(const void* text, size_t byteLength,
466 const SkScalar xpos[], SkScalar constY,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000467 const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000468 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000469 this->drawingCanvas()->drawPosTextH(text, byteLength, xpos, constY, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000470}
471
472void SkDeferredCanvas::drawTextOnPath(const void* text, size_t byteLength,
473 const SkPath& path,
474 const SkMatrix* matrix,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000475 const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000476 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000477 this->drawingCanvas()->drawTextOnPath(text, byteLength, path, matrix, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000478}
479
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000480void SkDeferredCanvas::drawPicture(SkPicture& picture) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000481 this->drawingCanvas()->drawPicture(picture);
junov@google.com4370aed2012-01-18 16:21:08 +0000482}
483
484void SkDeferredCanvas::drawVertices(VertexMode vmode, int vertexCount,
485 const SkPoint vertices[],
486 const SkPoint texs[],
487 const SkColor colors[], SkXfermode* xmode,
488 const uint16_t indices[], int indexCount,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000489 const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000490 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000491 this->drawingCanvas()->drawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
492 indices, indexCount, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000493}
494
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000495SkBounder* SkDeferredCanvas::setBounder(SkBounder* bounder) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000496 this->drawingCanvas()->setBounder(bounder);
497 return this->INHERITED::setBounder(bounder);
junov@google.com4370aed2012-01-18 16:21:08 +0000498}
499
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000500SkDrawFilter* SkDeferredCanvas::setDrawFilter(SkDrawFilter* filter) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000501 this->drawingCanvas()->setDrawFilter(filter);
502 return this->INHERITED::setDrawFilter(filter);
junov@google.com4370aed2012-01-18 16:21:08 +0000503}
504
505SkCanvas* SkDeferredCanvas::canvasForDrawIter() {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000506 return this->drawingCanvas();
junov@google.com4370aed2012-01-18 16:21:08 +0000507}
508
junov@chromium.org77eec242012-07-18 17:54:45 +0000509// SkDeferredCanvas::DeferredPipeController
510//-------------------------------------------
511
512SkDeferredCanvas::DeferredPipeController::DeferredPipeController() :
513 fAllocator(kMinBlockSize) {
514 fBlock = NULL;
515 fBytesWritten = 0;
516}
517
518SkDeferredCanvas::DeferredPipeController::~DeferredPipeController() {
519 fAllocator.reset();
520}
521
522void SkDeferredCanvas::DeferredPipeController::setPlaybackCanvas(SkCanvas* canvas) {
523 fReader.setCanvas(canvas);
524}
525
526void* SkDeferredCanvas::DeferredPipeController::requestBlock(size_t minRequest, size_t *actual) {
527 if (fBlock) {
528 // Save the previous block for later
529 PipeBlock previousBloc(fBlock, fBytesWritten);
530 fBlockList.push(previousBloc);
531 }
532 int32_t blockSize = SkMax32(minRequest, kMinBlockSize);
533 fBlock = fAllocator.allocThrow(blockSize);
534 fBytesWritten = 0;
535 *actual = blockSize;
536 return fBlock;
537}
538
539void SkDeferredCanvas::DeferredPipeController::notifyWritten(size_t bytes) {
540 fBytesWritten += bytes;
541}
542
543void SkDeferredCanvas::DeferredPipeController::playback() {
544
545 for (int currentBlock = 0; currentBlock < fBlockList.count(); currentBlock++ ) {
546 fReader.playback(fBlockList[currentBlock].fBlock, fBlockList[currentBlock].fSize);
547 }
548 fBlockList.reset();
549
550 if (fBlock) {
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000551 fReader.playback(fBlock, fBytesWritten);
junov@chromium.org77eec242012-07-18 17:54:45 +0000552 fBlock = NULL;
553 }
554
555 // Release all allocated blocks
556 fAllocator.reset();
557}
558
559void SkDeferredCanvas::DeferredPipeController::reset() {
560 fBlockList.reset();
561 fBlock = NULL;
562 fAllocator.reset();
563}
564
junov@google.com4370aed2012-01-18 16:21:08 +0000565// SkDeferredCanvas::DeferredDevice
566//------------------------------------
567
568SkDeferredCanvas::DeferredDevice::DeferredDevice(
569 SkDevice* immediateDevice, DeviceContext* deviceContext) :
570 SkDevice(SkBitmap::kNo_Config, immediateDevice->width(),
571 immediateDevice->height(), immediateDevice->isOpaque())
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000572 , fFreshFrame(true) {
573
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000574 fMaxRecordingStorageBytes = kDefaultMaxRecordingStorageBytes;
junov@google.com4370aed2012-01-18 16:21:08 +0000575 fDeviceContext = deviceContext;
576 SkSafeRef(fDeviceContext);
577 fImmediateDevice = immediateDevice; // ref counted via fImmediateCanvas
578 fImmediateCanvas = SkNEW_ARGS(SkCanvas, (fImmediateDevice));
junov@chromium.org77eec242012-07-18 17:54:45 +0000579 fPipeController.setPlaybackCanvas(fImmediateCanvas);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000580 this->beginRecording();
junov@google.com4370aed2012-01-18 16:21:08 +0000581}
582
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000583SkDeferredCanvas::DeferredDevice::~DeferredDevice() {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000584 this->flushPending();
junov@google.com4370aed2012-01-18 16:21:08 +0000585 SkSafeUnref(fImmediateCanvas);
586 SkSafeUnref(fDeviceContext);
587}
junov@chromium.org77eec242012-07-18 17:54:45 +0000588
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000589void SkDeferredCanvas::DeferredDevice::setMaxRecordingStorage(size_t maxStorage) {
590 fMaxRecordingStorageBytes = maxStorage;
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000591 this->recordingCanvas(); // Accessing the recording canvas applies the new limit.
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000592}
junov@chromium.org77eec242012-07-18 17:54:45 +0000593
594void SkDeferredCanvas::DeferredDevice::endRecording() {
junov@chromium.org77eec242012-07-18 17:54:45 +0000595 fPipeWriter.endRecording();
596 fPipeController.reset();
junov@chromium.org77eec242012-07-18 17:54:45 +0000597 fRecordingCanvas = NULL;
598}
599
600void SkDeferredCanvas::DeferredDevice::beginRecording() {
junov@chromium.org77eec242012-07-18 17:54:45 +0000601 fRecordingCanvas = fPipeWriter.startRecording(&fPipeController, 0);
junov@chromium.org77eec242012-07-18 17:54:45 +0000602}
junov@google.com4370aed2012-01-18 16:21:08 +0000603
604void SkDeferredCanvas::DeferredDevice::setDeviceContext(
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000605 DeviceContext* deviceContext) {
junov@google.com4370aed2012-01-18 16:21:08 +0000606 SkRefCnt_SafeAssign(fDeviceContext, deviceContext);
607}
608
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000609void SkDeferredCanvas::DeferredDevice::contentsCleared() {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000610 if (!fRecordingCanvas->isDrawingToLayer()) {
611 fFreshFrame = true;
junov@google.com4370aed2012-01-18 16:21:08 +0000612
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000613 // TODO: find a way to transfer the state stack and layers
614 // to the new recording canvas. For now, purging only works
615 // with an empty stack.
616 if (fRecordingCanvas->getSaveCount() == 0) {
junov@google.com4370aed2012-01-18 16:21:08 +0000617
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000618 // Save state that is trashed by the purge
619 SkDrawFilter* drawFilter = fRecordingCanvas->getDrawFilter();
620 SkSafeRef(drawFilter); // So that it survives the purge
621 SkMatrix matrix = fRecordingCanvas->getTotalMatrix();
622 SkRegion clipRegion = fRecordingCanvas->getTotalClip();
junov@google.com4370aed2012-01-18 16:21:08 +0000623
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000624 // beginRecording creates a new recording canvas and discards the
625 // old one, hence purging deferred draw ops.
junov@chromium.org77eec242012-07-18 17:54:45 +0000626 this->endRecording();
627 this->beginRecording();
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000628
629 // Restore pre-purge state
630 if (!clipRegion.isEmpty()) {
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000631 fRecordingCanvas->clipRegion(clipRegion,
632 SkRegion::kReplace_Op);
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000633 }
634 if (!matrix.isIdentity()) {
635 fRecordingCanvas->setMatrix(matrix);
636 }
637 if (drawFilter) {
638 fRecordingCanvas->setDrawFilter(drawFilter)->unref();
639 }
640 }
junov@google.com4370aed2012-01-18 16:21:08 +0000641 }
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000642}
643
644bool SkDeferredCanvas::DeferredDevice::isFreshFrame() {
645 bool ret = fFreshFrame;
646 fFreshFrame = false;
647 return ret;
junov@google.com4370aed2012-01-18 16:21:08 +0000648}
649
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000650void SkDeferredCanvas::DeferredDevice::flushPending() {
junov@chromium.org77eec242012-07-18 17:54:45 +0000651 if (!fPipeController.hasRecorded()) {
652 return;
653 }
junov@google.com4370aed2012-01-18 16:21:08 +0000654 if (fDeviceContext) {
655 fDeviceContext->prepareForDraw();
656 }
junov@chromium.org77eec242012-07-18 17:54:45 +0000657
junov@chromium.org77eec242012-07-18 17:54:45 +0000658 fPipeWriter.flushRecording(true);
659 fPipeController.playback();
junov@google.com4370aed2012-01-18 16:21:08 +0000660}
661
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000662void SkDeferredCanvas::DeferredDevice::flush() {
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000663 this->flushPending();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000664 fImmediateCanvas->flush();
junov@google.com4370aed2012-01-18 16:21:08 +0000665}
666
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000667size_t SkDeferredCanvas::DeferredDevice::freeMemoryIfPossible(size_t bytesToFree) {
668 return fPipeWriter.freeMemoryIfPossible(bytesToFree);
669}
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000670
671size_t SkDeferredCanvas::DeferredDevice::storageAllocatedForRecording() const {
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000672 return (fPipeController.storageAllocatedForRecording()
673 + fPipeWriter.storageAllocatedForRecording());
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000674}
675
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000676SkCanvas* SkDeferredCanvas::DeferredDevice::recordingCanvas() {
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000677 size_t storageAllocated = this->storageAllocatedForRecording();
678 if (storageAllocated > fMaxRecordingStorageBytes) {
679 // First, attempt to reduce cache without flushing
680 size_t tryFree = storageAllocated - fMaxRecordingStorageBytes;
681 if (this->freeMemoryIfPossible(tryFree) < tryFree) {
682 // Flush is necessary to free more space.
683 this->flushPending();
684 // Free as much as possible to avoid oscillating around fMaxRecordingStorageBytes
685 // which could cause a high flushing frequency.
686 this->freeMemoryIfPossible(~0);
687 }
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000688 }
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000689 return fRecordingCanvas;
690}
691
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000692uint32_t SkDeferredCanvas::DeferredDevice::getDeviceCapabilities() {
junov@google.com4370aed2012-01-18 16:21:08 +0000693 return fImmediateDevice->getDeviceCapabilities();
694}
695
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000696int SkDeferredCanvas::DeferredDevice::width() const {
junov@google.com4370aed2012-01-18 16:21:08 +0000697 return fImmediateDevice->width();
698}
699
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000700int SkDeferredCanvas::DeferredDevice::height() const {
junov@google.com4370aed2012-01-18 16:21:08 +0000701 return fImmediateDevice->height();
702}
703
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000704SkGpuRenderTarget* SkDeferredCanvas::DeferredDevice::accessRenderTarget() {
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000705 this->flushPending();
junov@google.com4370aed2012-01-18 16:21:08 +0000706 return fImmediateDevice->accessRenderTarget();
707}
708
709void SkDeferredCanvas::DeferredDevice::writePixels(const SkBitmap& bitmap,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000710 int x, int y, SkCanvas::Config8888 config8888) {
711
junov@google.com4370aed2012-01-18 16:21:08 +0000712 if (x <= 0 && y <= 0 && (x + bitmap.width()) >= width() &&
713 (y + bitmap.height()) >= height()) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000714 this->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000715 }
716
717 if (SkBitmap::kARGB_8888_Config == bitmap.config() &&
718 SkCanvas::kNative_Premul_Config8888 != config8888 &&
719 kPMColorAlias != config8888) {
720 //Special case config: no deferral
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000721 this->flushPending();
junov@google.com4370aed2012-01-18 16:21:08 +0000722 fImmediateDevice->writePixels(bitmap, x, y, config8888);
junov@chromium.org09640d62012-07-25 20:09:37 +0000723 return;
junov@google.com4370aed2012-01-18 16:21:08 +0000724 }
725
726 SkPaint paint;
727 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
junov@chromium.org10f7f972012-07-31 21:01:51 +0000728 if (shouldDrawImmediately(&bitmap, NULL)) {
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +0000729 this->flushPending();
730 fImmediateCanvas->drawSprite(bitmap, x, y, &paint);
731 } else {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000732 this->recordingCanvas()->drawSprite(bitmap, x, y, &paint);
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +0000733 }
junov@google.com4370aed2012-01-18 16:21:08 +0000734}
735
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000736const SkBitmap& SkDeferredCanvas::DeferredDevice::onAccessBitmap(SkBitmap*) {
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000737 this->flushPending();
junov@chromium.org1f9767c2012-02-07 16:27:57 +0000738 return fImmediateDevice->accessBitmap(false);
junov@google.com4370aed2012-01-18 16:21:08 +0000739}
740
741SkDevice* SkDeferredCanvas::DeferredDevice::onCreateCompatibleDevice(
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000742 SkBitmap::Config config, int width, int height, bool isOpaque,
743 Usage usage) {
744
junov@google.com4370aed2012-01-18 16:21:08 +0000745 // Save layer usage not supported, and not required by SkDeferredCanvas.
746 SkASSERT(usage != kSaveLayer_Usage);
747 // Create a compatible non-deferred device.
scroggo@google.comd7dbd422012-07-03 15:16:30 +0000748 SkAutoTUnref<SkDevice> compatibleDevice
749 (fImmediateDevice->createCompatibleDevice(config, width, height,
750 isOpaque));
junov@google.com4370aed2012-01-18 16:21:08 +0000751 return SkNEW_ARGS(DeferredDevice, (compatibleDevice, fDeviceContext));
752}
753
754bool SkDeferredCanvas::DeferredDevice::onReadPixels(
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000755 const SkBitmap& bitmap, int x, int y, SkCanvas::Config8888 config8888) {
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000756 this->flushPending();
junov@google.com4370aed2012-01-18 16:21:08 +0000757 return fImmediateCanvas->readPixels(const_cast<SkBitmap*>(&bitmap),
758 x, y, config8888);
759}