blob: 47e551ef5d650ec408ebadb8942db117b08962e6 [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
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.orgb10a6bd2012-07-25 17:27:13 +000024bool shouldDrawImmediately(const SkBitmap& bitmap) {
25 return bitmap.getTexture() && !bitmap.isImmutable();
26}
27}
28
29class AutoImmediateDrawIfNeeded {
30public:
31 AutoImmediateDrawIfNeeded(SkDeferredCanvas& canvas, const SkBitmap& bitmap) {
32 if (canvas.isDeferredDrawing() && shouldDrawImmediately(bitmap)) {
33 canvas.setDeferredDrawing(false);
34 fCanvas = &canvas;
35 } else {
36 fCanvas = NULL;
37 }
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +000038 }
39
40 ~AutoImmediateDrawIfNeeded() {
41 if (fCanvas) {
42 fCanvas->setDeferredDrawing(true);
43 }
44 }
45private:
46 SkDeferredCanvas* fCanvas;
47};
48
49namespace {
junov@google.com4370aed2012-01-18 16:21:08 +000050
junov@chromium.orgc16ca922012-02-24 22:06:27 +000051bool isPaintOpaque(const SkPaint* paint,
52 const SkBitmap* bmpReplacesShader = NULL) {
junov@google.com4370aed2012-01-18 16:21:08 +000053 // TODO: SkXfermode should have a virtual isOpaque method, which would
54 // make it possible to test modes that do not have a Coeff representation.
junov@chromium.org87f982c2012-02-23 21:34:34 +000055
56 if (!paint) {
57 return bmpReplacesShader ? bmpReplacesShader->isOpaque() : true;
58 }
59
junov@google.com4370aed2012-01-18 16:21:08 +000060 SkXfermode::Coeff srcCoeff, dstCoeff;
junov@chromium.org87f982c2012-02-23 21:34:34 +000061 if (SkXfermode::AsCoeff(paint->getXfermode(), &srcCoeff, &dstCoeff)){
junov@google.com4370aed2012-01-18 16:21:08 +000062 switch (dstCoeff) {
63 case SkXfermode::kZero_Coeff:
64 return true;
65 case SkXfermode::kISA_Coeff:
junov@chromium.org87f982c2012-02-23 21:34:34 +000066 if (paint->getAlpha() != 255) {
junov@google.com4370aed2012-01-18 16:21:08 +000067 break;
68 }
69 if (bmpReplacesShader) {
70 if (!bmpReplacesShader->isOpaque()) {
71 break;
72 }
junov@chromium.org87f982c2012-02-23 21:34:34 +000073 } else if (paint->getShader() && !paint->getShader()->isOpaque()) {
junov@google.com4370aed2012-01-18 16:21:08 +000074 break;
75 }
junov@chromium.orgc16ca922012-02-24 22:06:27 +000076 if (paint->getColorFilter() &&
77 ((paint->getColorFilter()->getFlags() &
junov@google.com4370aed2012-01-18 16:21:08 +000078 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
79 break;
80 }
81 return true;
82 case SkXfermode::kSA_Coeff:
junov@chromium.org87f982c2012-02-23 21:34:34 +000083 if (paint->getAlpha() != 0) {
junov@google.com4370aed2012-01-18 16:21:08 +000084 break;
85 }
junov@chromium.orgc16ca922012-02-24 22:06:27 +000086 if (paint->getColorFilter() &&
87 ((paint->getColorFilter()->getFlags() &
junov@google.com4370aed2012-01-18 16:21:08 +000088 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
89 break;
90 }
91 return true;
92 case SkXfermode::kSC_Coeff:
junov@chromium.org87f982c2012-02-23 21:34:34 +000093 if (paint->getColor() != 0) { // all components must be 0
junov@google.com4370aed2012-01-18 16:21:08 +000094 break;
95 }
junov@chromium.org87f982c2012-02-23 21:34:34 +000096 if (bmpReplacesShader || paint->getShader()) {
junov@google.com4370aed2012-01-18 16:21:08 +000097 break;
98 }
junov@chromium.orgc16ca922012-02-24 22:06:27 +000099 if (paint->getColorFilter() && (
100 (paint->getColorFilter()->getFlags() &
junov@google.com4370aed2012-01-18 16:21:08 +0000101 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
102 break;
103 }
104 return true;
105 default:
106 break;
107 }
108 }
109 return false;
110}
111
112} // unnamed namespace
113
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000114SkDeferredCanvas::SkDeferredCanvas() {
junov@google.com4370aed2012-01-18 16:21:08 +0000115 init();
116}
117
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000118SkDeferredCanvas::SkDeferredCanvas(SkDevice* device) {
junov@google.com4370aed2012-01-18 16:21:08 +0000119 init();
120 setDevice(device);
121}
122
123SkDeferredCanvas::SkDeferredCanvas(SkDevice* device,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000124 DeviceContext* deviceContext) {
junov@google.com4370aed2012-01-18 16:21:08 +0000125 init();
126 setDevice(device);
127 setDeviceContext(deviceContext);
128}
129
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000130void SkDeferredCanvas::init() {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000131 fDeferredDrawing = true; // On by default
junov@google.com4370aed2012-01-18 16:21:08 +0000132}
133
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000134void SkDeferredCanvas::setMaxRecordingStorage(size_t maxStorage) {
135 validate();
136 this->getDeferredDevice()->setMaxRecordingStorage(maxStorage);
137}
138
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000139void SkDeferredCanvas::validate() const {
junov@google.com4370aed2012-01-18 16:21:08 +0000140 SkASSERT(getDevice());
junov@google.com4370aed2012-01-18 16:21:08 +0000141}
142
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000143SkCanvas* SkDeferredCanvas::drawingCanvas() const {
144 validate();
145 return fDeferredDrawing ? getDeferredDevice()->recordingCanvas() :
146 getDeferredDevice()->immediateCanvas();
147}
148
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000149SkDeferredCanvas::DeferredDevice* SkDeferredCanvas::getDeferredDevice() const {
junov@google.com4370aed2012-01-18 16:21:08 +0000150 return static_cast<SkDeferredCanvas::DeferredDevice*>(getDevice());
151}
152
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000153void SkDeferredCanvas::setDeferredDrawing(bool val) {
junov@google.com4370aed2012-01-18 16:21:08 +0000154 validate(); // Must set device before calling this method
junov@google.com4370aed2012-01-18 16:21:08 +0000155 if (val != fDeferredDrawing) {
156 if (fDeferredDrawing) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000157 // Going live.
junov@google.com4370aed2012-01-18 16:21:08 +0000158 getDeferredDevice()->flushPending();
159 }
160 fDeferredDrawing = val;
161 }
162}
163
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +0000164bool SkDeferredCanvas::isDeferredDrawing() {
165 return fDeferredDrawing;
166}
167
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000168SkDeferredCanvas::~SkDeferredCanvas() {
junov@google.com4370aed2012-01-18 16:21:08 +0000169}
170
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000171SkDevice* SkDeferredCanvas::setDevice(SkDevice* device) {
junov@google.com4370aed2012-01-18 16:21:08 +0000172 INHERITED::setDevice(SkNEW_ARGS(DeferredDevice, (device)))->unref();
173 return device;
174}
175
176SkDeferredCanvas::DeviceContext* SkDeferredCanvas::setDeviceContext(
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000177 DeviceContext* deviceContext) {
178
junov@google.com4370aed2012-01-18 16:21:08 +0000179 DeferredDevice* deferredDevice = getDeferredDevice();
180 SkASSERT(deferredDevice);
181 if (deferredDevice) {
182 deferredDevice->setDeviceContext(deviceContext);
183 }
184 return deviceContext;
185}
186
187bool SkDeferredCanvas::isFullFrame(const SkRect* rect,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000188 const SkPaint* paint) const {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000189 SkCanvas* canvas = drawingCanvas();
junov@google.com4370aed2012-01-18 16:21:08 +0000190 SkISize canvasSize = getDeviceSize();
191 if (rect) {
192 if (!canvas->getTotalMatrix().rectStaysRect()) {
193 return false; // conservative
194 }
195
196 SkRect transformedRect;
197 canvas->getTotalMatrix().mapRect(&transformedRect, *rect);
198
199 if (paint) {
200 SkPaint::Style paintStyle = paint->getStyle();
201 if (!(paintStyle == SkPaint::kFill_Style ||
202 paintStyle == SkPaint::kStrokeAndFill_Style)) {
203 return false;
204 }
205 if (paint->getMaskFilter() || paint->getLooper()
206 || paint->getPathEffect() || paint->getImageFilter()) {
207 return false; // conservative
208 }
209 }
210
211 // The following test holds with AA enabled, and is conservative
212 // by a 0.5 pixel margin with AA disabled
junov@chromium.orgb1e218e2012-02-13 22:27:58 +0000213 if (transformedRect.fLeft > SkIntToScalar(0) ||
214 transformedRect.fTop > SkIntToScalar(0) ||
215 transformedRect.fRight < SkIntToScalar(canvasSize.fWidth) ||
216 transformedRect.fBottom < SkIntToScalar(canvasSize.fHeight)) {
junov@google.com4370aed2012-01-18 16:21:08 +0000217 return false;
218 }
219 }
220
221 switch (canvas->getClipType()) {
222 case SkCanvas::kRect_ClipType :
223 {
224 SkIRect bounds;
225 canvas->getClipDeviceBounds(&bounds);
226 if (bounds.fLeft > 0 || bounds.fTop > 0 ||
227 bounds.fRight < canvasSize.fWidth ||
228 bounds.fBottom < canvasSize.fHeight)
229 return false;
230 }
231 break;
232 case SkCanvas::kComplex_ClipType :
233 return false; // conservative
234 case SkCanvas::kEmpty_ClipType:
235 default:
236 break;
237 };
238
239 return true;
240}
241
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000242int SkDeferredCanvas::save(SaveFlags flags) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000243 drawingCanvas()->save(flags);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000244 return this->INHERITED::save(flags);
junov@google.com4370aed2012-01-18 16:21:08 +0000245}
246
247int SkDeferredCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000248 SaveFlags flags) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000249 drawingCanvas()->saveLayer(bounds, paint, flags);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000250 int count = this->INHERITED::save(flags);
251 this->clipRectBounds(bounds, flags, NULL);
252 return count;
junov@google.com4370aed2012-01-18 16:21:08 +0000253}
254
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000255void SkDeferredCanvas::restore() {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000256 drawingCanvas()->restore();
junov@chromium.orga907ac32012-02-24 21:54:07 +0000257 this->INHERITED::restore();
junov@google.com4370aed2012-01-18 16:21:08 +0000258}
259
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000260bool SkDeferredCanvas::isDrawingToLayer() const {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000261 return drawingCanvas()->isDrawingToLayer();
junov@google.com4370aed2012-01-18 16:21:08 +0000262}
263
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000264bool SkDeferredCanvas::translate(SkScalar dx, SkScalar dy) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000265 drawingCanvas()->translate(dx, dy);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000266 return this->INHERITED::translate(dx, dy);
junov@google.com4370aed2012-01-18 16:21:08 +0000267}
268
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000269bool SkDeferredCanvas::scale(SkScalar sx, SkScalar sy) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000270 drawingCanvas()->scale(sx, sy);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000271 return this->INHERITED::scale(sx, sy);
junov@google.com4370aed2012-01-18 16:21:08 +0000272}
273
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000274bool SkDeferredCanvas::rotate(SkScalar degrees) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000275 drawingCanvas()->rotate(degrees);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000276 return this->INHERITED::rotate(degrees);
junov@google.com4370aed2012-01-18 16:21:08 +0000277}
278
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000279bool SkDeferredCanvas::skew(SkScalar sx, SkScalar sy) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000280 drawingCanvas()->skew(sx, sy);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000281 return this->INHERITED::skew(sx, sy);
junov@google.com4370aed2012-01-18 16:21:08 +0000282}
283
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000284bool SkDeferredCanvas::concat(const SkMatrix& matrix) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000285 drawingCanvas()->concat(matrix);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000286 return this->INHERITED::concat(matrix);
junov@google.com4370aed2012-01-18 16:21:08 +0000287}
288
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000289void SkDeferredCanvas::setMatrix(const SkMatrix& matrix) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000290 drawingCanvas()->setMatrix(matrix);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000291 this->INHERITED::setMatrix(matrix);
junov@google.com4370aed2012-01-18 16:21:08 +0000292}
293
294bool SkDeferredCanvas::clipRect(const SkRect& rect,
295 SkRegion::Op op,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000296 bool doAntiAlias) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000297 drawingCanvas()->clipRect(rect, op, doAntiAlias);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000298 return this->INHERITED::clipRect(rect, op, doAntiAlias);
junov@google.com4370aed2012-01-18 16:21:08 +0000299}
300
301bool SkDeferredCanvas::clipPath(const SkPath& path,
302 SkRegion::Op op,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000303 bool doAntiAlias) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000304 drawingCanvas()->clipPath(path, op, doAntiAlias);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000305 return this->INHERITED::clipPath(path, op, doAntiAlias);
junov@google.com4370aed2012-01-18 16:21:08 +0000306}
307
308bool SkDeferredCanvas::clipRegion(const SkRegion& deviceRgn,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000309 SkRegion::Op op) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000310 drawingCanvas()->clipRegion(deviceRgn, op);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000311 return this->INHERITED::clipRegion(deviceRgn, op);
junov@google.com4370aed2012-01-18 16:21:08 +0000312}
313
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000314void SkDeferredCanvas::clear(SkColor color) {
junov@google.com4370aed2012-01-18 16:21:08 +0000315 // purge pending commands
316 if (fDeferredDrawing) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000317 getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000318 }
319
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000320 drawingCanvas()->clear(color);
junov@google.com4370aed2012-01-18 16:21:08 +0000321}
322
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000323void SkDeferredCanvas::drawPaint(const SkPaint& paint) {
324 if (fDeferredDrawing && isFullFrame(NULL, &paint) &&
325 isPaintOpaque(&paint)) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000326 getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000327 }
328
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000329 drawingCanvas()->drawPaint(paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000330}
331
332void SkDeferredCanvas::drawPoints(PointMode mode, size_t count,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000333 const SkPoint pts[], const SkPaint& paint) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000334 drawingCanvas()->drawPoints(mode, count, pts, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000335}
336
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000337void SkDeferredCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
338 if (fDeferredDrawing && isFullFrame(&rect, &paint) &&
339 isPaintOpaque(&paint)) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000340 getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000341 }
342
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000343 drawingCanvas()->drawRect(rect, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000344}
345
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000346void SkDeferredCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000347 drawingCanvas()->drawPath(path, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000348}
349
350void SkDeferredCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000351 SkScalar top, const SkPaint* paint) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000352 SkRect bitmapRect = SkRect::MakeXYWH(left, top,
353 SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height()));
junov@google.com4370aed2012-01-18 16:21:08 +0000354 if (fDeferredDrawing &&
355 isFullFrame(&bitmapRect, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000356 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000357 getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000358 }
359
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +0000360 AutoImmediateDrawIfNeeded autoDraw(*this, bitmap);
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000361 drawingCanvas()->drawBitmap(bitmap, left, top, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000362}
363
364void SkDeferredCanvas::drawBitmapRect(const SkBitmap& bitmap,
365 const SkIRect* src,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000366 const SkRect& dst,
367 const SkPaint* paint) {
junov@google.com4370aed2012-01-18 16:21:08 +0000368 if (fDeferredDrawing &&
369 isFullFrame(&dst, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000370 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000371 getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000372 }
373
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +0000374 AutoImmediateDrawIfNeeded autoDraw(*this, bitmap);
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000375 drawingCanvas()->drawBitmapRect(bitmap, src,
junov@google.com4370aed2012-01-18 16:21:08 +0000376 dst, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000377}
378
379
380void SkDeferredCanvas::drawBitmapMatrix(const SkBitmap& bitmap,
381 const SkMatrix& m,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000382 const SkPaint* paint) {
junov@google.com4370aed2012-01-18 16:21:08 +0000383 // TODO: reset recording canvas if paint+bitmap is opaque and clip rect
384 // covers canvas entirely and transformed bitmap covers canvas entirely
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +0000385 AutoImmediateDrawIfNeeded autoDraw(*this, bitmap);
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000386 drawingCanvas()->drawBitmapMatrix(bitmap, m, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000387}
388
389void SkDeferredCanvas::drawBitmapNine(const SkBitmap& bitmap,
390 const SkIRect& center, const SkRect& dst,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000391 const SkPaint* paint) {
junov@google.com4370aed2012-01-18 16:21:08 +0000392 // TODO: reset recording canvas if paint+bitmap is opaque and clip rect
393 // covers canvas entirely and dst covers canvas entirely
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +0000394 AutoImmediateDrawIfNeeded autoDraw(*this, bitmap);
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000395 drawingCanvas()->drawBitmapNine(bitmap, center,
junov@google.com4370aed2012-01-18 16:21:08 +0000396 dst, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000397}
398
399void SkDeferredCanvas::drawSprite(const SkBitmap& bitmap, int left, int top,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000400 const SkPaint* paint) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000401 SkRect bitmapRect = SkRect::MakeXYWH(
402 SkIntToScalar(left),
403 SkIntToScalar(top),
404 SkIntToScalar(bitmap.width()),
405 SkIntToScalar(bitmap.height()));
junov@google.com4370aed2012-01-18 16:21:08 +0000406 if (fDeferredDrawing &&
407 isFullFrame(&bitmapRect, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000408 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000409 getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000410 }
411
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +0000412 AutoImmediateDrawIfNeeded autoDraw(*this, bitmap);
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000413 drawingCanvas()->drawSprite(bitmap, left, top,
junov@google.com4370aed2012-01-18 16:21:08 +0000414 paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000415}
416
417void SkDeferredCanvas::drawText(const void* text, size_t byteLength,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000418 SkScalar x, SkScalar y, const SkPaint& paint) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000419 drawingCanvas()->drawText(text, byteLength, x, y, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000420}
421
422void SkDeferredCanvas::drawPosText(const void* text, size_t byteLength,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000423 const SkPoint pos[], const SkPaint& paint) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000424 drawingCanvas()->drawPosText(text, byteLength, pos, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000425}
426
427void SkDeferredCanvas::drawPosTextH(const void* text, size_t byteLength,
428 const SkScalar xpos[], SkScalar constY,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000429 const SkPaint& paint) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000430 drawingCanvas()->drawPosTextH(text, byteLength, xpos, constY, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000431}
432
433void SkDeferredCanvas::drawTextOnPath(const void* text, size_t byteLength,
434 const SkPath& path,
435 const SkMatrix* matrix,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000436 const SkPaint& paint) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000437 drawingCanvas()->drawTextOnPath(text, byteLength,
junov@google.com4370aed2012-01-18 16:21:08 +0000438 path, matrix,
439 paint);
440}
441
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000442void SkDeferredCanvas::drawPicture(SkPicture& picture) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000443 drawingCanvas()->drawPicture(picture);
junov@google.com4370aed2012-01-18 16:21:08 +0000444}
445
446void SkDeferredCanvas::drawVertices(VertexMode vmode, int vertexCount,
447 const SkPoint vertices[],
448 const SkPoint texs[],
449 const SkColor colors[], SkXfermode* xmode,
450 const uint16_t indices[], int indexCount,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000451 const SkPaint& paint) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000452 drawingCanvas()->drawVertices(vmode, vertexCount,
junov@google.com4370aed2012-01-18 16:21:08 +0000453 vertices, texs,
454 colors, xmode,
455 indices, indexCount,
456 paint);
457}
458
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000459SkBounder* SkDeferredCanvas::setBounder(SkBounder* bounder) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000460 drawingCanvas()->setBounder(bounder);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000461 return INHERITED::setBounder(bounder);
junov@google.com4370aed2012-01-18 16:21:08 +0000462}
463
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000464SkDrawFilter* SkDeferredCanvas::setDrawFilter(SkDrawFilter* filter) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000465 drawingCanvas()->setDrawFilter(filter);
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000466 return INHERITED::setDrawFilter(filter);
junov@google.com4370aed2012-01-18 16:21:08 +0000467}
468
469SkCanvas* SkDeferredCanvas::canvasForDrawIter() {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000470 return drawingCanvas();
junov@google.com4370aed2012-01-18 16:21:08 +0000471}
472
junov@chromium.org77eec242012-07-18 17:54:45 +0000473#if SK_DEFERRED_CANVAS_USES_GPIPE
474
475// SkDeferredCanvas::DeferredPipeController
476//-------------------------------------------
477
478SkDeferredCanvas::DeferredPipeController::DeferredPipeController() :
479 fAllocator(kMinBlockSize) {
480 fBlock = NULL;
481 fBytesWritten = 0;
482}
483
484SkDeferredCanvas::DeferredPipeController::~DeferredPipeController() {
485 fAllocator.reset();
486}
487
488void SkDeferredCanvas::DeferredPipeController::setPlaybackCanvas(SkCanvas* canvas) {
489 fReader.setCanvas(canvas);
490}
491
492void* SkDeferredCanvas::DeferredPipeController::requestBlock(size_t minRequest, size_t *actual) {
493 if (fBlock) {
494 // Save the previous block for later
495 PipeBlock previousBloc(fBlock, fBytesWritten);
496 fBlockList.push(previousBloc);
497 }
498 int32_t blockSize = SkMax32(minRequest, kMinBlockSize);
499 fBlock = fAllocator.allocThrow(blockSize);
500 fBytesWritten = 0;
501 *actual = blockSize;
502 return fBlock;
503}
504
505void SkDeferredCanvas::DeferredPipeController::notifyWritten(size_t bytes) {
506 fBytesWritten += bytes;
507}
508
509void SkDeferredCanvas::DeferredPipeController::playback() {
510
511 for (int currentBlock = 0; currentBlock < fBlockList.count(); currentBlock++ ) {
512 fReader.playback(fBlockList[currentBlock].fBlock, fBlockList[currentBlock].fSize);
513 }
514 fBlockList.reset();
515
516 if (fBlock) {
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000517 fReader.playback(fBlock, fBytesWritten);
junov@chromium.org77eec242012-07-18 17:54:45 +0000518 fBlock = NULL;
519 }
520
521 // Release all allocated blocks
522 fAllocator.reset();
523}
524
525void SkDeferredCanvas::DeferredPipeController::reset() {
526 fBlockList.reset();
527 fBlock = NULL;
528 fAllocator.reset();
529}
530
531#endif // SK_DEFERRED_CANVAS_USES_GPIPE
532
junov@google.com4370aed2012-01-18 16:21:08 +0000533// SkDeferredCanvas::DeferredDevice
534//------------------------------------
535
536SkDeferredCanvas::DeferredDevice::DeferredDevice(
537 SkDevice* immediateDevice, DeviceContext* deviceContext) :
538 SkDevice(SkBitmap::kNo_Config, immediateDevice->width(),
539 immediateDevice->height(), immediateDevice->isOpaque())
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000540 , fFreshFrame(true) {
541
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000542 fMaxRecordingStorageBytes = kDefaultMaxRecordingStorageBytes;
junov@google.com4370aed2012-01-18 16:21:08 +0000543 fDeviceContext = deviceContext;
544 SkSafeRef(fDeviceContext);
545 fImmediateDevice = immediateDevice; // ref counted via fImmediateCanvas
546 fImmediateCanvas = SkNEW_ARGS(SkCanvas, (fImmediateDevice));
junov@chromium.org77eec242012-07-18 17:54:45 +0000547#if SK_DEFERRED_CANVAS_USES_GPIPE
548 fPipeController.setPlaybackCanvas(fImmediateCanvas);
549#endif
550 beginRecording();
junov@google.com4370aed2012-01-18 16:21:08 +0000551}
552
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000553SkDeferredCanvas::DeferredDevice::~DeferredDevice() {
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +0000554 flushPending();
junov@google.com4370aed2012-01-18 16:21:08 +0000555 SkSafeUnref(fImmediateCanvas);
556 SkSafeUnref(fDeviceContext);
557}
junov@chromium.org77eec242012-07-18 17:54:45 +0000558
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000559void SkDeferredCanvas::DeferredDevice::setMaxRecordingStorage(size_t maxStorage) {
560 fMaxRecordingStorageBytes = maxStorage;
561 recordingCanvas(); // Accessing the recording canvas applies the new limit.
562}
junov@chromium.org77eec242012-07-18 17:54:45 +0000563
564void SkDeferredCanvas::DeferredDevice::endRecording() {
565#if SK_DEFERRED_CANVAS_USES_GPIPE
566 fPipeWriter.endRecording();
567 fPipeController.reset();
568#else
569 fPicture.endRecording();
570#endif
571 fRecordingCanvas = NULL;
572}
573
574void SkDeferredCanvas::DeferredDevice::beginRecording() {
575#if SK_DEFERRED_CANVAS_USES_GPIPE
576 fRecordingCanvas = fPipeWriter.startRecording(&fPipeController, 0);
577#else
578 fRecordingCanvas = fPicture.beginRecording(fImmediateDevice->width(),
djsollen@google.com7dade422012-07-27 15:58:23 +0000579 fImmediateDevice->height());
junov@chromium.org77eec242012-07-18 17:54:45 +0000580#endif
581}
junov@google.com4370aed2012-01-18 16:21:08 +0000582
583void SkDeferredCanvas::DeferredDevice::setDeviceContext(
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000584 DeviceContext* deviceContext) {
junov@google.com4370aed2012-01-18 16:21:08 +0000585 SkRefCnt_SafeAssign(fDeviceContext, deviceContext);
586}
587
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000588void SkDeferredCanvas::DeferredDevice::contentsCleared() {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000589 if (!fRecordingCanvas->isDrawingToLayer()) {
590 fFreshFrame = true;
junov@google.com4370aed2012-01-18 16:21:08 +0000591
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000592 // TODO: find a way to transfer the state stack and layers
593 // to the new recording canvas. For now, purging only works
594 // with an empty stack.
595 if (fRecordingCanvas->getSaveCount() == 0) {
junov@google.com4370aed2012-01-18 16:21:08 +0000596
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000597 // Save state that is trashed by the purge
598 SkDrawFilter* drawFilter = fRecordingCanvas->getDrawFilter();
599 SkSafeRef(drawFilter); // So that it survives the purge
600 SkMatrix matrix = fRecordingCanvas->getTotalMatrix();
601 SkRegion clipRegion = fRecordingCanvas->getTotalClip();
junov@google.com4370aed2012-01-18 16:21:08 +0000602
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000603 // beginRecording creates a new recording canvas and discards the
604 // old one, hence purging deferred draw ops.
junov@chromium.org77eec242012-07-18 17:54:45 +0000605 this->endRecording();
606 this->beginRecording();
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000607
608 // Restore pre-purge state
609 if (!clipRegion.isEmpty()) {
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000610 fRecordingCanvas->clipRegion(clipRegion,
611 SkRegion::kReplace_Op);
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000612 }
613 if (!matrix.isIdentity()) {
614 fRecordingCanvas->setMatrix(matrix);
615 }
616 if (drawFilter) {
617 fRecordingCanvas->setDrawFilter(drawFilter)->unref();
618 }
619 }
junov@google.com4370aed2012-01-18 16:21:08 +0000620 }
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000621}
622
623bool SkDeferredCanvas::DeferredDevice::isFreshFrame() {
624 bool ret = fFreshFrame;
625 fFreshFrame = false;
626 return ret;
junov@google.com4370aed2012-01-18 16:21:08 +0000627}
628
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000629void SkDeferredCanvas::DeferredDevice::flushPending() {
junov@chromium.org77eec242012-07-18 17:54:45 +0000630#if SK_DEFERRED_CANVAS_USES_GPIPE
631 if (!fPipeController.hasRecorded()) {
632 return;
633 }
634#else
junov@chromium.org4866cc02012-06-01 21:23:07 +0000635 if (!fPicture.hasRecorded()) {
636 return;
637 }
junov@chromium.org77eec242012-07-18 17:54:45 +0000638#endif
junov@google.com4370aed2012-01-18 16:21:08 +0000639 if (fDeviceContext) {
640 fDeviceContext->prepareForDraw();
641 }
junov@chromium.org77eec242012-07-18 17:54:45 +0000642
643#if SK_DEFERRED_CANVAS_USES_GPIPE
644 fPipeWriter.flushRecording(true);
645 fPipeController.playback();
646#else
junov@google.com4370aed2012-01-18 16:21:08 +0000647 fPicture.draw(fImmediateCanvas);
junov@chromium.org77eec242012-07-18 17:54:45 +0000648 this->beginRecording();
649#endif
junov@google.com4370aed2012-01-18 16:21:08 +0000650}
651
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000652void SkDeferredCanvas::DeferredDevice::flush() {
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000653 this->flushPending();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000654 fImmediateCanvas->flush();
junov@google.com4370aed2012-01-18 16:21:08 +0000655}
656
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000657SkCanvas* SkDeferredCanvas::DeferredDevice::recordingCanvas() {
658#if SK_DEFERRED_CANVAS_USES_GPIPE
scroggo@google.com15011ee2012-07-26 20:03:32 +0000659 if (fPipeController.storageAllocatedForRecording()
660 + fPipeWriter.storageAllocatedForRecording()
661 > fMaxRecordingStorageBytes) {
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000662 this->flushPending();
663 }
664#endif
665 return fRecordingCanvas;
666}
667
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000668uint32_t SkDeferredCanvas::DeferredDevice::getDeviceCapabilities() {
junov@google.com4370aed2012-01-18 16:21:08 +0000669 return fImmediateDevice->getDeviceCapabilities();
670}
671
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000672int SkDeferredCanvas::DeferredDevice::width() const {
junov@google.com4370aed2012-01-18 16:21:08 +0000673 return fImmediateDevice->width();
674}
675
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000676int SkDeferredCanvas::DeferredDevice::height() const {
junov@google.com4370aed2012-01-18 16:21:08 +0000677 return fImmediateDevice->height();
678}
679
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000680SkGpuRenderTarget* SkDeferredCanvas::DeferredDevice::accessRenderTarget() {
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000681 this->flushPending();
junov@google.com4370aed2012-01-18 16:21:08 +0000682 return fImmediateDevice->accessRenderTarget();
683}
684
685void SkDeferredCanvas::DeferredDevice::writePixels(const SkBitmap& bitmap,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000686 int x, int y, SkCanvas::Config8888 config8888) {
687
junov@google.com4370aed2012-01-18 16:21:08 +0000688 if (x <= 0 && y <= 0 && (x + bitmap.width()) >= width() &&
689 (y + bitmap.height()) >= height()) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000690 contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000691 }
692
693 if (SkBitmap::kARGB_8888_Config == bitmap.config() &&
694 SkCanvas::kNative_Premul_Config8888 != config8888 &&
695 kPMColorAlias != config8888) {
696 //Special case config: no deferral
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000697 this->flushPending();
junov@google.com4370aed2012-01-18 16:21:08 +0000698 fImmediateDevice->writePixels(bitmap, x, y, config8888);
junov@chromium.org09640d62012-07-25 20:09:37 +0000699 return;
junov@google.com4370aed2012-01-18 16:21:08 +0000700 }
701
702 SkPaint paint;
703 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +0000704 if (shouldDrawImmediately(bitmap)) {
705 this->flushPending();
706 fImmediateCanvas->drawSprite(bitmap, x, y, &paint);
707 } else {
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +0000708 recordingCanvas()->drawSprite(bitmap, x, y, &paint);
709 }
junov@google.com4370aed2012-01-18 16:21:08 +0000710}
711
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000712const SkBitmap& SkDeferredCanvas::DeferredDevice::onAccessBitmap(SkBitmap*) {
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000713 this->flushPending();
junov@chromium.org1f9767c2012-02-07 16:27:57 +0000714 return fImmediateDevice->accessBitmap(false);
junov@google.com4370aed2012-01-18 16:21:08 +0000715}
716
717SkDevice* SkDeferredCanvas::DeferredDevice::onCreateCompatibleDevice(
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000718 SkBitmap::Config config, int width, int height, bool isOpaque,
719 Usage usage) {
720
junov@google.com4370aed2012-01-18 16:21:08 +0000721 // Save layer usage not supported, and not required by SkDeferredCanvas.
722 SkASSERT(usage != kSaveLayer_Usage);
723 // Create a compatible non-deferred device.
scroggo@google.comd7dbd422012-07-03 15:16:30 +0000724 SkAutoTUnref<SkDevice> compatibleDevice
725 (fImmediateDevice->createCompatibleDevice(config, width, height,
726 isOpaque));
junov@google.com4370aed2012-01-18 16:21:08 +0000727 return SkNEW_ARGS(DeferredDevice, (compatibleDevice, fDeviceContext));
728}
729
730bool SkDeferredCanvas::DeferredDevice::onReadPixels(
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000731 const SkBitmap& bitmap, int x, int y, SkCanvas::Config8888 config8888) {
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000732 this->flushPending();
junov@google.com4370aed2012-01-18 16:21:08 +0000733 return fImmediateCanvas->readPixels(const_cast<SkBitmap*>(&bitmap),
734 x, y, config8888);
735}