blob: 568f9a79a49511f4793eef0d792fd8de7cf709f5 [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@google.com4370aed2012-01-18 16:21:08 +000018namespace {
19
junov@chromium.orgc16ca922012-02-24 22:06:27 +000020bool isPaintOpaque(const SkPaint* paint,
21 const SkBitmap* bmpReplacesShader = NULL) {
junov@google.com4370aed2012-01-18 16:21:08 +000022 // TODO: SkXfermode should have a virtual isOpaque method, which would
23 // make it possible to test modes that do not have a Coeff representation.
junov@chromium.org87f982c2012-02-23 21:34:34 +000024
25 if (!paint) {
26 return bmpReplacesShader ? bmpReplacesShader->isOpaque() : true;
27 }
28
junov@google.com4370aed2012-01-18 16:21:08 +000029 SkXfermode::Coeff srcCoeff, dstCoeff;
junov@chromium.org87f982c2012-02-23 21:34:34 +000030 if (SkXfermode::AsCoeff(paint->getXfermode(), &srcCoeff, &dstCoeff)){
junov@google.com4370aed2012-01-18 16:21:08 +000031 switch (dstCoeff) {
32 case SkXfermode::kZero_Coeff:
33 return true;
34 case SkXfermode::kISA_Coeff:
junov@chromium.org87f982c2012-02-23 21:34:34 +000035 if (paint->getAlpha() != 255) {
junov@google.com4370aed2012-01-18 16:21:08 +000036 break;
37 }
38 if (bmpReplacesShader) {
39 if (!bmpReplacesShader->isOpaque()) {
40 break;
41 }
junov@chromium.org87f982c2012-02-23 21:34:34 +000042 } else if (paint->getShader() && !paint->getShader()->isOpaque()) {
junov@google.com4370aed2012-01-18 16:21:08 +000043 break;
44 }
junov@chromium.orgc16ca922012-02-24 22:06:27 +000045 if (paint->getColorFilter() &&
46 ((paint->getColorFilter()->getFlags() &
junov@google.com4370aed2012-01-18 16:21:08 +000047 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
48 break;
49 }
50 return true;
51 case SkXfermode::kSA_Coeff:
junov@chromium.org87f982c2012-02-23 21:34:34 +000052 if (paint->getAlpha() != 0) {
junov@google.com4370aed2012-01-18 16:21:08 +000053 break;
54 }
junov@chromium.orgc16ca922012-02-24 22:06:27 +000055 if (paint->getColorFilter() &&
56 ((paint->getColorFilter()->getFlags() &
junov@google.com4370aed2012-01-18 16:21:08 +000057 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
58 break;
59 }
60 return true;
61 case SkXfermode::kSC_Coeff:
junov@chromium.org87f982c2012-02-23 21:34:34 +000062 if (paint->getColor() != 0) { // all components must be 0
junov@google.com4370aed2012-01-18 16:21:08 +000063 break;
64 }
junov@chromium.org87f982c2012-02-23 21:34:34 +000065 if (bmpReplacesShader || paint->getShader()) {
junov@google.com4370aed2012-01-18 16:21:08 +000066 break;
67 }
junov@chromium.orgc16ca922012-02-24 22:06:27 +000068 if (paint->getColorFilter() && (
69 (paint->getColorFilter()->getFlags() &
junov@google.com4370aed2012-01-18 16:21:08 +000070 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
71 break;
72 }
73 return true;
74 default:
75 break;
76 }
77 }
78 return false;
79}
80
81} // unnamed namespace
82
junov@chromium.orgc16ca922012-02-24 22:06:27 +000083SkDeferredCanvas::SkDeferredCanvas() {
junov@google.com4370aed2012-01-18 16:21:08 +000084 init();
85}
86
junov@chromium.orgc16ca922012-02-24 22:06:27 +000087SkDeferredCanvas::SkDeferredCanvas(SkDevice* device) {
junov@google.com4370aed2012-01-18 16:21:08 +000088 init();
89 setDevice(device);
90}
91
92SkDeferredCanvas::SkDeferredCanvas(SkDevice* device,
junov@chromium.orgc16ca922012-02-24 22:06:27 +000093 DeviceContext* deviceContext) {
junov@google.com4370aed2012-01-18 16:21:08 +000094 init();
95 setDevice(device);
96 setDeviceContext(deviceContext);
97}
98
junov@chromium.orgc16ca922012-02-24 22:06:27 +000099void SkDeferredCanvas::init() {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000100 fDeferredDrawing = true; // On by default
junov@google.com4370aed2012-01-18 16:21:08 +0000101}
102
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000103void SkDeferredCanvas::validate() const {
junov@google.com4370aed2012-01-18 16:21:08 +0000104 SkASSERT(getDevice());
junov@google.com4370aed2012-01-18 16:21:08 +0000105}
106
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000107SkCanvas* SkDeferredCanvas::drawingCanvas() const {
108 validate();
109 return fDeferredDrawing ? getDeferredDevice()->recordingCanvas() :
110 getDeferredDevice()->immediateCanvas();
111}
112
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000113void SkDeferredCanvas::flushIfNeeded(const SkBitmap& bitmap) {
junov@google.com4370aed2012-01-18 16:21:08 +0000114 validate();
115 if (fDeferredDrawing) {
116 getDeferredDevice()->flushIfNeeded(bitmap);
117 }
118}
119
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000120SkDeferredCanvas::DeferredDevice* SkDeferredCanvas::getDeferredDevice() const {
junov@google.com4370aed2012-01-18 16:21:08 +0000121 return static_cast<SkDeferredCanvas::DeferredDevice*>(getDevice());
122}
123
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000124void SkDeferredCanvas::setDeferredDrawing(bool val) {
junov@google.com4370aed2012-01-18 16:21:08 +0000125 validate(); // Must set device before calling this method
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000126 SkASSERT(drawingCanvas()->getSaveCount() == 1);
junov@google.com4370aed2012-01-18 16:21:08 +0000127 if (val != fDeferredDrawing) {
128 if (fDeferredDrawing) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000129 // Going live.
junov@google.com4370aed2012-01-18 16:21:08 +0000130 getDeferredDevice()->flushPending();
131 }
132 fDeferredDrawing = val;
133 }
134}
135
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000136SkDeferredCanvas::~SkDeferredCanvas() {
junov@google.com4370aed2012-01-18 16:21:08 +0000137}
138
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000139SkDevice* SkDeferredCanvas::setDevice(SkDevice* device) {
junov@google.com4370aed2012-01-18 16:21:08 +0000140 INHERITED::setDevice(SkNEW_ARGS(DeferredDevice, (device)))->unref();
141 return device;
142}
143
144SkDeferredCanvas::DeviceContext* SkDeferredCanvas::setDeviceContext(
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000145 DeviceContext* deviceContext) {
146
junov@google.com4370aed2012-01-18 16:21:08 +0000147 DeferredDevice* deferredDevice = getDeferredDevice();
148 SkASSERT(deferredDevice);
149 if (deferredDevice) {
150 deferredDevice->setDeviceContext(deviceContext);
151 }
152 return deviceContext;
153}
154
155bool SkDeferredCanvas::isFullFrame(const SkRect* rect,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000156 const SkPaint* paint) const {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000157 SkCanvas* canvas = drawingCanvas();
junov@google.com4370aed2012-01-18 16:21:08 +0000158 SkISize canvasSize = getDeviceSize();
159 if (rect) {
160 if (!canvas->getTotalMatrix().rectStaysRect()) {
161 return false; // conservative
162 }
163
164 SkRect transformedRect;
165 canvas->getTotalMatrix().mapRect(&transformedRect, *rect);
166
167 if (paint) {
168 SkPaint::Style paintStyle = paint->getStyle();
169 if (!(paintStyle == SkPaint::kFill_Style ||
170 paintStyle == SkPaint::kStrokeAndFill_Style)) {
171 return false;
172 }
173 if (paint->getMaskFilter() || paint->getLooper()
174 || paint->getPathEffect() || paint->getImageFilter()) {
175 return false; // conservative
176 }
177 }
178
179 // The following test holds with AA enabled, and is conservative
180 // by a 0.5 pixel margin with AA disabled
junov@chromium.orgb1e218e2012-02-13 22:27:58 +0000181 if (transformedRect.fLeft > SkIntToScalar(0) ||
182 transformedRect.fTop > SkIntToScalar(0) ||
183 transformedRect.fRight < SkIntToScalar(canvasSize.fWidth) ||
184 transformedRect.fBottom < SkIntToScalar(canvasSize.fHeight)) {
junov@google.com4370aed2012-01-18 16:21:08 +0000185 return false;
186 }
187 }
188
189 switch (canvas->getClipType()) {
190 case SkCanvas::kRect_ClipType :
191 {
192 SkIRect bounds;
193 canvas->getClipDeviceBounds(&bounds);
194 if (bounds.fLeft > 0 || bounds.fTop > 0 ||
195 bounds.fRight < canvasSize.fWidth ||
196 bounds.fBottom < canvasSize.fHeight)
197 return false;
198 }
199 break;
200 case SkCanvas::kComplex_ClipType :
201 return false; // conservative
202 case SkCanvas::kEmpty_ClipType:
203 default:
204 break;
205 };
206
207 return true;
208}
209
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000210int SkDeferredCanvas::save(SaveFlags flags) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000211 drawingCanvas()->save(flags);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000212 return this->INHERITED::save(flags);
junov@google.com4370aed2012-01-18 16:21:08 +0000213}
214
215int SkDeferredCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000216 SaveFlags flags) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000217 drawingCanvas()->saveLayer(bounds, paint, flags);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000218 int count = this->INHERITED::save(flags);
219 this->clipRectBounds(bounds, flags, NULL);
220 return count;
junov@google.com4370aed2012-01-18 16:21:08 +0000221}
222
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000223void SkDeferredCanvas::restore() {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000224 drawingCanvas()->restore();
junov@chromium.orga907ac32012-02-24 21:54:07 +0000225 this->INHERITED::restore();
junov@google.com4370aed2012-01-18 16:21:08 +0000226}
227
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000228bool SkDeferredCanvas::isDrawingToLayer() const {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000229 return drawingCanvas()->isDrawingToLayer();
junov@google.com4370aed2012-01-18 16:21:08 +0000230}
231
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000232bool SkDeferredCanvas::translate(SkScalar dx, SkScalar dy) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000233 drawingCanvas()->translate(dx, dy);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000234 return this->INHERITED::translate(dx, dy);
junov@google.com4370aed2012-01-18 16:21:08 +0000235}
236
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000237bool SkDeferredCanvas::scale(SkScalar sx, SkScalar sy) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000238 drawingCanvas()->scale(sx, sy);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000239 return this->INHERITED::scale(sx, sy);
junov@google.com4370aed2012-01-18 16:21:08 +0000240}
241
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000242bool SkDeferredCanvas::rotate(SkScalar degrees) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000243 drawingCanvas()->rotate(degrees);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000244 return this->INHERITED::rotate(degrees);
junov@google.com4370aed2012-01-18 16:21:08 +0000245}
246
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000247bool SkDeferredCanvas::skew(SkScalar sx, SkScalar sy) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000248 drawingCanvas()->skew(sx, sy);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000249 return this->INHERITED::skew(sx, sy);
junov@google.com4370aed2012-01-18 16:21:08 +0000250}
251
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000252bool SkDeferredCanvas::concat(const SkMatrix& matrix) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000253 drawingCanvas()->concat(matrix);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000254 return this->INHERITED::concat(matrix);
junov@google.com4370aed2012-01-18 16:21:08 +0000255}
256
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000257void SkDeferredCanvas::setMatrix(const SkMatrix& matrix) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000258 drawingCanvas()->setMatrix(matrix);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000259 this->INHERITED::setMatrix(matrix);
junov@google.com4370aed2012-01-18 16:21:08 +0000260}
261
262bool SkDeferredCanvas::clipRect(const SkRect& rect,
263 SkRegion::Op op,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000264 bool doAntiAlias) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000265 drawingCanvas()->clipRect(rect, op, doAntiAlias);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000266 return this->INHERITED::clipRect(rect, op, doAntiAlias);
junov@google.com4370aed2012-01-18 16:21:08 +0000267}
268
269bool SkDeferredCanvas::clipPath(const SkPath& path,
270 SkRegion::Op op,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000271 bool doAntiAlias) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000272 drawingCanvas()->clipPath(path, op, doAntiAlias);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000273 return this->INHERITED::clipPath(path, op, doAntiAlias);
junov@google.com4370aed2012-01-18 16:21:08 +0000274}
275
276bool SkDeferredCanvas::clipRegion(const SkRegion& deviceRgn,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000277 SkRegion::Op op) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000278 drawingCanvas()->clipRegion(deviceRgn, op);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000279 return this->INHERITED::clipRegion(deviceRgn, op);
junov@google.com4370aed2012-01-18 16:21:08 +0000280}
281
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000282void SkDeferredCanvas::clear(SkColor color) {
junov@google.com4370aed2012-01-18 16:21:08 +0000283 // purge pending commands
284 if (fDeferredDrawing) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000285 getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000286 }
287
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000288 drawingCanvas()->clear(color);
junov@google.com4370aed2012-01-18 16:21:08 +0000289}
290
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000291void SkDeferredCanvas::drawPaint(const SkPaint& paint) {
292 if (fDeferredDrawing && isFullFrame(NULL, &paint) &&
293 isPaintOpaque(&paint)) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000294 getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000295 }
296
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000297 drawingCanvas()->drawPaint(paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000298}
299
300void SkDeferredCanvas::drawPoints(PointMode mode, size_t count,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000301 const SkPoint pts[], const SkPaint& paint) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000302 drawingCanvas()->drawPoints(mode, count, pts, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000303}
304
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000305void SkDeferredCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
306 if (fDeferredDrawing && isFullFrame(&rect, &paint) &&
307 isPaintOpaque(&paint)) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000308 getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000309 }
310
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000311 drawingCanvas()->drawRect(rect, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000312}
313
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000314void SkDeferredCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000315 drawingCanvas()->drawPath(path, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000316}
317
318void SkDeferredCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000319 SkScalar top, const SkPaint* paint) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000320 SkRect bitmapRect = SkRect::MakeXYWH(left, top,
321 SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height()));
junov@google.com4370aed2012-01-18 16:21:08 +0000322 if (fDeferredDrawing &&
323 isFullFrame(&bitmapRect, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000324 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000325 getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000326 }
327
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000328 drawingCanvas()->drawBitmap(bitmap, left, top, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000329 flushIfNeeded(bitmap);
330}
331
332void SkDeferredCanvas::drawBitmapRect(const SkBitmap& bitmap,
333 const SkIRect* src,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000334 const SkRect& dst,
335 const SkPaint* paint) {
junov@google.com4370aed2012-01-18 16:21:08 +0000336 if (fDeferredDrawing &&
337 isFullFrame(&dst, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000338 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000339 getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000340 }
341
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000342 drawingCanvas()->drawBitmapRect(bitmap, src,
junov@google.com4370aed2012-01-18 16:21:08 +0000343 dst, paint);
344 flushIfNeeded(bitmap);
345}
346
347
348void SkDeferredCanvas::drawBitmapMatrix(const SkBitmap& bitmap,
349 const SkMatrix& m,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000350 const SkPaint* paint) {
junov@google.com4370aed2012-01-18 16:21:08 +0000351 // TODO: reset recording canvas if paint+bitmap is opaque and clip rect
352 // covers canvas entirely and transformed bitmap covers canvas entirely
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000353 drawingCanvas()->drawBitmapMatrix(bitmap, m, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000354 flushIfNeeded(bitmap);
355}
356
357void SkDeferredCanvas::drawBitmapNine(const SkBitmap& bitmap,
358 const SkIRect& center, const SkRect& dst,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000359 const SkPaint* paint) {
junov@google.com4370aed2012-01-18 16:21:08 +0000360 // TODO: reset recording canvas if paint+bitmap is opaque and clip rect
361 // covers canvas entirely and dst covers canvas entirely
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000362 drawingCanvas()->drawBitmapNine(bitmap, center,
junov@google.com4370aed2012-01-18 16:21:08 +0000363 dst, paint);
364 flushIfNeeded(bitmap);
365}
366
367void SkDeferredCanvas::drawSprite(const SkBitmap& bitmap, int left, int top,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000368 const SkPaint* paint) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000369 SkRect bitmapRect = SkRect::MakeXYWH(
370 SkIntToScalar(left),
371 SkIntToScalar(top),
372 SkIntToScalar(bitmap.width()),
373 SkIntToScalar(bitmap.height()));
junov@google.com4370aed2012-01-18 16:21:08 +0000374 if (fDeferredDrawing &&
375 isFullFrame(&bitmapRect, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000376 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000377 getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000378 }
379
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000380 drawingCanvas()->drawSprite(bitmap, left, top,
junov@google.com4370aed2012-01-18 16:21:08 +0000381 paint);
382 flushIfNeeded(bitmap);
383}
384
385void SkDeferredCanvas::drawText(const void* text, size_t byteLength,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000386 SkScalar x, SkScalar y, const SkPaint& paint) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000387 drawingCanvas()->drawText(text, byteLength, x, y, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000388}
389
390void SkDeferredCanvas::drawPosText(const void* text, size_t byteLength,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000391 const SkPoint pos[], const SkPaint& paint) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000392 drawingCanvas()->drawPosText(text, byteLength, pos, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000393}
394
395void SkDeferredCanvas::drawPosTextH(const void* text, size_t byteLength,
396 const SkScalar xpos[], SkScalar constY,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000397 const SkPaint& paint) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000398 drawingCanvas()->drawPosTextH(text, byteLength, xpos, constY, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000399}
400
401void SkDeferredCanvas::drawTextOnPath(const void* text, size_t byteLength,
402 const SkPath& path,
403 const SkMatrix* matrix,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000404 const SkPaint& paint) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000405 drawingCanvas()->drawTextOnPath(text, byteLength,
junov@google.com4370aed2012-01-18 16:21:08 +0000406 path, matrix,
407 paint);
408}
409
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000410void SkDeferredCanvas::drawPicture(SkPicture& picture) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000411 drawingCanvas()->drawPicture(picture);
junov@google.com4370aed2012-01-18 16:21:08 +0000412}
413
414void SkDeferredCanvas::drawVertices(VertexMode vmode, int vertexCount,
415 const SkPoint vertices[],
416 const SkPoint texs[],
417 const SkColor colors[], SkXfermode* xmode,
418 const uint16_t indices[], int indexCount,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000419 const SkPaint& paint) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000420 drawingCanvas()->drawVertices(vmode, vertexCount,
junov@google.com4370aed2012-01-18 16:21:08 +0000421 vertices, texs,
422 colors, xmode,
423 indices, indexCount,
424 paint);
425}
426
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000427SkBounder* SkDeferredCanvas::setBounder(SkBounder* bounder) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000428 drawingCanvas()->setBounder(bounder);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000429 return INHERITED::setBounder(bounder);
junov@google.com4370aed2012-01-18 16:21:08 +0000430}
431
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000432SkDrawFilter* SkDeferredCanvas::setDrawFilter(SkDrawFilter* filter) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000433 drawingCanvas()->setDrawFilter(filter);
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000434 return INHERITED::setDrawFilter(filter);
junov@google.com4370aed2012-01-18 16:21:08 +0000435}
436
437SkCanvas* SkDeferredCanvas::canvasForDrawIter() {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000438 return drawingCanvas();
junov@google.com4370aed2012-01-18 16:21:08 +0000439}
440
junov@chromium.org77eec242012-07-18 17:54:45 +0000441#if SK_DEFERRED_CANVAS_USES_GPIPE
442
443// SkDeferredCanvas::DeferredPipeController
444//-------------------------------------------
445
446SkDeferredCanvas::DeferredPipeController::DeferredPipeController() :
447 fAllocator(kMinBlockSize) {
448 fBlock = NULL;
449 fBytesWritten = 0;
450}
451
452SkDeferredCanvas::DeferredPipeController::~DeferredPipeController() {
453 fAllocator.reset();
454}
455
456void SkDeferredCanvas::DeferredPipeController::setPlaybackCanvas(SkCanvas* canvas) {
457 fReader.setCanvas(canvas);
458}
459
460void* SkDeferredCanvas::DeferredPipeController::requestBlock(size_t minRequest, size_t *actual) {
461 if (fBlock) {
462 // Save the previous block for later
463 PipeBlock previousBloc(fBlock, fBytesWritten);
464 fBlockList.push(previousBloc);
465 }
466 int32_t blockSize = SkMax32(minRequest, kMinBlockSize);
467 fBlock = fAllocator.allocThrow(blockSize);
468 fBytesWritten = 0;
469 *actual = blockSize;
470 return fBlock;
471}
472
473void SkDeferredCanvas::DeferredPipeController::notifyWritten(size_t bytes) {
474 fBytesWritten += bytes;
475}
476
477void SkDeferredCanvas::DeferredPipeController::playback() {
478
479 for (int currentBlock = 0; currentBlock < fBlockList.count(); currentBlock++ ) {
480 fReader.playback(fBlockList[currentBlock].fBlock, fBlockList[currentBlock].fSize);
481 }
482 fBlockList.reset();
483
484 if (fBlock) {
485 fReader.playback(fBlock,fBytesWritten);
486 fBlock = NULL;
487 }
488
489 // Release all allocated blocks
490 fAllocator.reset();
491}
492
493void SkDeferredCanvas::DeferredPipeController::reset() {
494 fBlockList.reset();
495 fBlock = NULL;
496 fAllocator.reset();
497}
498
499#endif // SK_DEFERRED_CANVAS_USES_GPIPE
500
junov@google.com4370aed2012-01-18 16:21:08 +0000501// SkDeferredCanvas::DeferredDevice
502//------------------------------------
503
504SkDeferredCanvas::DeferredDevice::DeferredDevice(
505 SkDevice* immediateDevice, DeviceContext* deviceContext) :
506 SkDevice(SkBitmap::kNo_Config, immediateDevice->width(),
507 immediateDevice->height(), immediateDevice->isOpaque())
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000508 , fFreshFrame(true) {
509
junov@google.com4370aed2012-01-18 16:21:08 +0000510 fDeviceContext = deviceContext;
511 SkSafeRef(fDeviceContext);
512 fImmediateDevice = immediateDevice; // ref counted via fImmediateCanvas
513 fImmediateCanvas = SkNEW_ARGS(SkCanvas, (fImmediateDevice));
junov@chromium.org77eec242012-07-18 17:54:45 +0000514#if SK_DEFERRED_CANVAS_USES_GPIPE
515 fPipeController.setPlaybackCanvas(fImmediateCanvas);
516#endif
517 beginRecording();
junov@google.com4370aed2012-01-18 16:21:08 +0000518}
519
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000520SkDeferredCanvas::DeferredDevice::~DeferredDevice() {
junov@google.com4370aed2012-01-18 16:21:08 +0000521 SkSafeUnref(fImmediateCanvas);
522 SkSafeUnref(fDeviceContext);
523}
junov@chromium.org77eec242012-07-18 17:54:45 +0000524
525
526void SkDeferredCanvas::DeferredDevice::endRecording() {
527#if SK_DEFERRED_CANVAS_USES_GPIPE
528 fPipeWriter.endRecording();
529 fPipeController.reset();
530#else
531 fPicture.endRecording();
532#endif
533 fRecordingCanvas = NULL;
534}
535
536void SkDeferredCanvas::DeferredDevice::beginRecording() {
537#if SK_DEFERRED_CANVAS_USES_GPIPE
538 fRecordingCanvas = fPipeWriter.startRecording(&fPipeController, 0);
539#else
540 fRecordingCanvas = fPicture.beginRecording(fImmediateDevice->width(),
541 fImmediateDevice->height(),
542 SkPicture::kFlattenMutableNonTexturePixelRefs_RecordingFlag);
543#endif
544}
junov@google.com4370aed2012-01-18 16:21:08 +0000545
546void SkDeferredCanvas::DeferredDevice::setDeviceContext(
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000547 DeviceContext* deviceContext) {
junov@google.com4370aed2012-01-18 16:21:08 +0000548 SkRefCnt_SafeAssign(fDeviceContext, deviceContext);
549}
550
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000551void SkDeferredCanvas::DeferredDevice::contentsCleared() {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000552 if (!fRecordingCanvas->isDrawingToLayer()) {
553 fFreshFrame = true;
junov@google.com4370aed2012-01-18 16:21:08 +0000554
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000555 // TODO: find a way to transfer the state stack and layers
556 // to the new recording canvas. For now, purging only works
557 // with an empty stack.
558 if (fRecordingCanvas->getSaveCount() == 0) {
junov@google.com4370aed2012-01-18 16:21:08 +0000559
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000560 // Save state that is trashed by the purge
561 SkDrawFilter* drawFilter = fRecordingCanvas->getDrawFilter();
562 SkSafeRef(drawFilter); // So that it survives the purge
563 SkMatrix matrix = fRecordingCanvas->getTotalMatrix();
564 SkRegion clipRegion = fRecordingCanvas->getTotalClip();
junov@google.com4370aed2012-01-18 16:21:08 +0000565
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000566 // beginRecording creates a new recording canvas and discards the
567 // old one, hence purging deferred draw ops.
junov@chromium.org77eec242012-07-18 17:54:45 +0000568 this->endRecording();
569 this->beginRecording();
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000570
571 // Restore pre-purge state
572 if (!clipRegion.isEmpty()) {
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000573 fRecordingCanvas->clipRegion(clipRegion,
574 SkRegion::kReplace_Op);
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000575 }
576 if (!matrix.isIdentity()) {
577 fRecordingCanvas->setMatrix(matrix);
578 }
579 if (drawFilter) {
580 fRecordingCanvas->setDrawFilter(drawFilter)->unref();
581 }
582 }
junov@google.com4370aed2012-01-18 16:21:08 +0000583 }
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000584}
585
586bool SkDeferredCanvas::DeferredDevice::isFreshFrame() {
587 bool ret = fFreshFrame;
588 fFreshFrame = false;
589 return ret;
junov@google.com4370aed2012-01-18 16:21:08 +0000590}
591
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000592void SkDeferredCanvas::DeferredDevice::flushPending() {
junov@chromium.org77eec242012-07-18 17:54:45 +0000593#if SK_DEFERRED_CANVAS_USES_GPIPE
594 if (!fPipeController.hasRecorded()) {
595 return;
596 }
597#else
junov@chromium.org4866cc02012-06-01 21:23:07 +0000598 if (!fPicture.hasRecorded()) {
599 return;
600 }
junov@chromium.org77eec242012-07-18 17:54:45 +0000601#endif
junov@google.com4370aed2012-01-18 16:21:08 +0000602 if (fDeviceContext) {
603 fDeviceContext->prepareForDraw();
604 }
junov@chromium.org77eec242012-07-18 17:54:45 +0000605
606#if SK_DEFERRED_CANVAS_USES_GPIPE
607 fPipeWriter.flushRecording(true);
608 fPipeController.playback();
609#else
junov@google.com4370aed2012-01-18 16:21:08 +0000610 fPicture.draw(fImmediateCanvas);
junov@chromium.org77eec242012-07-18 17:54:45 +0000611 this->beginRecording();
612#endif
junov@google.com4370aed2012-01-18 16:21:08 +0000613}
614
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000615void SkDeferredCanvas::DeferredDevice::flush() {
junov@google.com4370aed2012-01-18 16:21:08 +0000616 flushPending();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000617 fImmediateCanvas->flush();
junov@google.com4370aed2012-01-18 16:21:08 +0000618}
619
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000620void SkDeferredCanvas::DeferredDevice::flushIfNeeded(const SkBitmap& bitmap) {
junov@chromium.org77eec242012-07-18 17:54:45 +0000621#if SK_DEFERRED_CANVAS_USES_GPIPE
622 if (bitmap.isImmutable()) {
623 // FIXME: Make SkGPipe flatten software-backed non-immutable bitmaps
624 return;
625 }
626#else
junov@chromium.org4866cc02012-06-01 21:23:07 +0000627 if (bitmap.isImmutable() || fPicture.willFlattenPixelsOnRecord(bitmap)) {
628 return; // safe to defer.
junov@google.com4370aed2012-01-18 16:21:08 +0000629 }
junov@chromium.org77eec242012-07-18 17:54:45 +0000630#endif
junov@google.com4370aed2012-01-18 16:21:08 +0000631
632 // For now, drawing a writable bitmap triggers a flush
633 // TODO: implement read-only semantics and auto buffer duplication on write
634 // in SkBitmap/SkPixelRef, which will make deferral possible in this case.
635 flushPending();
636}
637
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000638uint32_t SkDeferredCanvas::DeferredDevice::getDeviceCapabilities() {
junov@google.com4370aed2012-01-18 16:21:08 +0000639 return fImmediateDevice->getDeviceCapabilities();
640}
641
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000642int SkDeferredCanvas::DeferredDevice::width() const {
junov@google.com4370aed2012-01-18 16:21:08 +0000643 return fImmediateDevice->width();
644}
645
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000646int SkDeferredCanvas::DeferredDevice::height() const {
junov@google.com4370aed2012-01-18 16:21:08 +0000647 return fImmediateDevice->height();
648}
649
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000650SkGpuRenderTarget* SkDeferredCanvas::DeferredDevice::accessRenderTarget() {
junov@google.com4370aed2012-01-18 16:21:08 +0000651 flushPending();
652 return fImmediateDevice->accessRenderTarget();
653}
654
655void SkDeferredCanvas::DeferredDevice::writePixels(const SkBitmap& bitmap,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000656 int x, int y, SkCanvas::Config8888 config8888) {
657
junov@google.com4370aed2012-01-18 16:21:08 +0000658 if (x <= 0 && y <= 0 && (x + bitmap.width()) >= width() &&
659 (y + bitmap.height()) >= height()) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000660 contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000661 }
662
663 if (SkBitmap::kARGB_8888_Config == bitmap.config() &&
664 SkCanvas::kNative_Premul_Config8888 != config8888 &&
665 kPMColorAlias != config8888) {
666 //Special case config: no deferral
667 flushPending();
668 fImmediateDevice->writePixels(bitmap, x, y, config8888);
669 }
670
671 SkPaint paint;
672 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
673 fRecordingCanvas->drawSprite(bitmap, x, y, &paint);
674 flushIfNeeded(bitmap);
675}
676
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000677const SkBitmap& SkDeferredCanvas::DeferredDevice::onAccessBitmap(SkBitmap*) {
junov@google.com4370aed2012-01-18 16:21:08 +0000678 flushPending();
junov@chromium.org1f9767c2012-02-07 16:27:57 +0000679 return fImmediateDevice->accessBitmap(false);
junov@google.com4370aed2012-01-18 16:21:08 +0000680}
681
682SkDevice* SkDeferredCanvas::DeferredDevice::onCreateCompatibleDevice(
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000683 SkBitmap::Config config, int width, int height, bool isOpaque,
684 Usage usage) {
685
junov@google.com4370aed2012-01-18 16:21:08 +0000686 // Save layer usage not supported, and not required by SkDeferredCanvas.
687 SkASSERT(usage != kSaveLayer_Usage);
688 // Create a compatible non-deferred device.
scroggo@google.comd7dbd422012-07-03 15:16:30 +0000689 SkAutoTUnref<SkDevice> compatibleDevice
690 (fImmediateDevice->createCompatibleDevice(config, width, height,
691 isOpaque));
junov@google.com4370aed2012-01-18 16:21:08 +0000692 return SkNEW_ARGS(DeferredDevice, (compatibleDevice, fDeviceContext));
693}
694
695bool SkDeferredCanvas::DeferredDevice::onReadPixels(
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000696 const SkBitmap& bitmap, int x, int y, SkCanvas::Config8888 config8888) {
junov@google.com4370aed2012-01-18 16:21:08 +0000697 flushPending();
698 return fImmediateCanvas->readPixels(const_cast<SkBitmap*>(&bitmap),
699 x, y, config8888);
700}