blob: ac2b3cce1a53bbe6f2747df960e6f29d2e4398bf [file] [log] [blame]
junov@google.com4370aed2012-01-18 16:21:08 +00001
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9#include "SkDeferredCanvas.h"
10
11#include "SkPaint.h"
12#include "SkShader.h"
13#include "SkColorFilter.h"
14#include "SkDrawFilter.h"
15
16namespace {
17
junov@chromium.orgc16ca922012-02-24 22:06:27 +000018bool isPaintOpaque(const SkPaint* paint,
19 const SkBitmap* bmpReplacesShader = NULL) {
junov@google.com4370aed2012-01-18 16:21:08 +000020 // TODO: SkXfermode should have a virtual isOpaque method, which would
21 // make it possible to test modes that do not have a Coeff representation.
junov@chromium.org87f982c2012-02-23 21:34:34 +000022
23 if (!paint) {
24 return bmpReplacesShader ? bmpReplacesShader->isOpaque() : true;
25 }
26
junov@google.com4370aed2012-01-18 16:21:08 +000027 SkXfermode::Coeff srcCoeff, dstCoeff;
junov@chromium.org87f982c2012-02-23 21:34:34 +000028 if (SkXfermode::AsCoeff(paint->getXfermode(), &srcCoeff, &dstCoeff)){
junov@google.com4370aed2012-01-18 16:21:08 +000029 switch (dstCoeff) {
30 case SkXfermode::kZero_Coeff:
31 return true;
32 case SkXfermode::kISA_Coeff:
junov@chromium.org87f982c2012-02-23 21:34:34 +000033 if (paint->getAlpha() != 255) {
junov@google.com4370aed2012-01-18 16:21:08 +000034 break;
35 }
36 if (bmpReplacesShader) {
37 if (!bmpReplacesShader->isOpaque()) {
38 break;
39 }
junov@chromium.org87f982c2012-02-23 21:34:34 +000040 } else if (paint->getShader() && !paint->getShader()->isOpaque()) {
junov@google.com4370aed2012-01-18 16:21:08 +000041 break;
42 }
junov@chromium.orgc16ca922012-02-24 22:06:27 +000043 if (paint->getColorFilter() &&
44 ((paint->getColorFilter()->getFlags() &
junov@google.com4370aed2012-01-18 16:21:08 +000045 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
46 break;
47 }
48 return true;
49 case SkXfermode::kSA_Coeff:
junov@chromium.org87f982c2012-02-23 21:34:34 +000050 if (paint->getAlpha() != 0) {
junov@google.com4370aed2012-01-18 16:21:08 +000051 break;
52 }
junov@chromium.orgc16ca922012-02-24 22:06:27 +000053 if (paint->getColorFilter() &&
54 ((paint->getColorFilter()->getFlags() &
junov@google.com4370aed2012-01-18 16:21:08 +000055 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
56 break;
57 }
58 return true;
59 case SkXfermode::kSC_Coeff:
junov@chromium.org87f982c2012-02-23 21:34:34 +000060 if (paint->getColor() != 0) { // all components must be 0
junov@google.com4370aed2012-01-18 16:21:08 +000061 break;
62 }
junov@chromium.org87f982c2012-02-23 21:34:34 +000063 if (bmpReplacesShader || paint->getShader()) {
junov@google.com4370aed2012-01-18 16:21:08 +000064 break;
65 }
junov@chromium.orgc16ca922012-02-24 22:06:27 +000066 if (paint->getColorFilter() && (
67 (paint->getColorFilter()->getFlags() &
junov@google.com4370aed2012-01-18 16:21:08 +000068 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
69 break;
70 }
71 return true;
72 default:
73 break;
74 }
75 }
76 return false;
77}
78
79} // unnamed namespace
80
junov@chromium.orgc16ca922012-02-24 22:06:27 +000081SkDeferredCanvas::SkDeferredCanvas() {
junov@google.com4370aed2012-01-18 16:21:08 +000082 init();
83}
84
junov@chromium.orgc16ca922012-02-24 22:06:27 +000085SkDeferredCanvas::SkDeferredCanvas(SkDevice* device) {
junov@google.com4370aed2012-01-18 16:21:08 +000086 init();
87 setDevice(device);
88}
89
90SkDeferredCanvas::SkDeferredCanvas(SkDevice* device,
junov@chromium.orgc16ca922012-02-24 22:06:27 +000091 DeviceContext* deviceContext) {
junov@google.com4370aed2012-01-18 16:21:08 +000092 init();
93 setDevice(device);
94 setDeviceContext(deviceContext);
95}
96
junov@chromium.orgc16ca922012-02-24 22:06:27 +000097void SkDeferredCanvas::init() {
junov@chromium.org5e5a0952012-02-28 15:27:59 +000098 fDeferredDrawing = true; // On by default
junov@google.com4370aed2012-01-18 16:21:08 +000099}
100
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000101void SkDeferredCanvas::validate() const {
junov@google.com4370aed2012-01-18 16:21:08 +0000102 SkASSERT(getDevice());
junov@google.com4370aed2012-01-18 16:21:08 +0000103}
104
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000105SkCanvas* SkDeferredCanvas::drawingCanvas() const {
106 validate();
107 return fDeferredDrawing ? getDeferredDevice()->recordingCanvas() :
108 getDeferredDevice()->immediateCanvas();
109}
110
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000111void SkDeferredCanvas::flushIfNeeded(const SkBitmap& bitmap) {
junov@google.com4370aed2012-01-18 16:21:08 +0000112 validate();
113 if (fDeferredDrawing) {
114 getDeferredDevice()->flushIfNeeded(bitmap);
115 }
116}
117
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000118SkDeferredCanvas::DeferredDevice* SkDeferredCanvas::getDeferredDevice() const {
junov@google.com4370aed2012-01-18 16:21:08 +0000119 return static_cast<SkDeferredCanvas::DeferredDevice*>(getDevice());
120}
121
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000122void SkDeferredCanvas::setDeferredDrawing(bool val) {
junov@google.com4370aed2012-01-18 16:21:08 +0000123 validate(); // Must set device before calling this method
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000124 SkASSERT(drawingCanvas()->getSaveCount() == 1);
junov@google.com4370aed2012-01-18 16:21:08 +0000125 if (val != fDeferredDrawing) {
126 if (fDeferredDrawing) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000127 // Going live.
junov@google.com4370aed2012-01-18 16:21:08 +0000128 getDeferredDevice()->flushPending();
129 }
130 fDeferredDrawing = val;
131 }
132}
133
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000134SkDeferredCanvas::~SkDeferredCanvas() {
junov@google.com4370aed2012-01-18 16:21:08 +0000135}
136
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000137SkDevice* SkDeferredCanvas::setDevice(SkDevice* device) {
junov@google.com4370aed2012-01-18 16:21:08 +0000138 INHERITED::setDevice(SkNEW_ARGS(DeferredDevice, (device)))->unref();
139 return device;
140}
141
142SkDeferredCanvas::DeviceContext* SkDeferredCanvas::setDeviceContext(
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000143 DeviceContext* deviceContext) {
144
junov@google.com4370aed2012-01-18 16:21:08 +0000145 DeferredDevice* deferredDevice = getDeferredDevice();
146 SkASSERT(deferredDevice);
147 if (deferredDevice) {
148 deferredDevice->setDeviceContext(deviceContext);
149 }
150 return deviceContext;
151}
152
153bool SkDeferredCanvas::isFullFrame(const SkRect* rect,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000154 const SkPaint* paint) const {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000155 SkCanvas* canvas = drawingCanvas();
junov@google.com4370aed2012-01-18 16:21:08 +0000156 SkISize canvasSize = getDeviceSize();
157 if (rect) {
158 if (!canvas->getTotalMatrix().rectStaysRect()) {
159 return false; // conservative
160 }
161
162 SkRect transformedRect;
163 canvas->getTotalMatrix().mapRect(&transformedRect, *rect);
164
165 if (paint) {
166 SkPaint::Style paintStyle = paint->getStyle();
167 if (!(paintStyle == SkPaint::kFill_Style ||
168 paintStyle == SkPaint::kStrokeAndFill_Style)) {
169 return false;
170 }
171 if (paint->getMaskFilter() || paint->getLooper()
172 || paint->getPathEffect() || paint->getImageFilter()) {
173 return false; // conservative
174 }
175 }
176
177 // The following test holds with AA enabled, and is conservative
178 // by a 0.5 pixel margin with AA disabled
junov@chromium.orgb1e218e2012-02-13 22:27:58 +0000179 if (transformedRect.fLeft > SkIntToScalar(0) ||
180 transformedRect.fTop > SkIntToScalar(0) ||
181 transformedRect.fRight < SkIntToScalar(canvasSize.fWidth) ||
182 transformedRect.fBottom < SkIntToScalar(canvasSize.fHeight)) {
junov@google.com4370aed2012-01-18 16:21:08 +0000183 return false;
184 }
185 }
186
187 switch (canvas->getClipType()) {
188 case SkCanvas::kRect_ClipType :
189 {
190 SkIRect bounds;
191 canvas->getClipDeviceBounds(&bounds);
192 if (bounds.fLeft > 0 || bounds.fTop > 0 ||
193 bounds.fRight < canvasSize.fWidth ||
194 bounds.fBottom < canvasSize.fHeight)
195 return false;
196 }
197 break;
198 case SkCanvas::kComplex_ClipType :
199 return false; // conservative
200 case SkCanvas::kEmpty_ClipType:
201 default:
202 break;
203 };
204
205 return true;
206}
207
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000208int SkDeferredCanvas::save(SaveFlags flags) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000209 drawingCanvas()->save(flags);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000210 return this->INHERITED::save(flags);
junov@google.com4370aed2012-01-18 16:21:08 +0000211}
212
213int SkDeferredCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000214 SaveFlags flags) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000215 drawingCanvas()->saveLayer(bounds, paint, flags);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000216 int count = this->INHERITED::save(flags);
217 this->clipRectBounds(bounds, flags, NULL);
218 return count;
junov@google.com4370aed2012-01-18 16:21:08 +0000219}
220
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000221void SkDeferredCanvas::restore() {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000222 drawingCanvas()->restore();
junov@chromium.orga907ac32012-02-24 21:54:07 +0000223 this->INHERITED::restore();
junov@google.com4370aed2012-01-18 16:21:08 +0000224}
225
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000226bool SkDeferredCanvas::isDrawingToLayer() const {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000227 return drawingCanvas()->isDrawingToLayer();
junov@google.com4370aed2012-01-18 16:21:08 +0000228}
229
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000230bool SkDeferredCanvas::translate(SkScalar dx, SkScalar dy) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000231 drawingCanvas()->translate(dx, dy);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000232 return this->INHERITED::translate(dx, dy);
junov@google.com4370aed2012-01-18 16:21:08 +0000233}
234
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000235bool SkDeferredCanvas::scale(SkScalar sx, SkScalar sy) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000236 drawingCanvas()->scale(sx, sy);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000237 return this->INHERITED::scale(sx, sy);
junov@google.com4370aed2012-01-18 16:21:08 +0000238}
239
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000240bool SkDeferredCanvas::rotate(SkScalar degrees) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000241 drawingCanvas()->rotate(degrees);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000242 return this->INHERITED::rotate(degrees);
junov@google.com4370aed2012-01-18 16:21:08 +0000243}
244
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000245bool SkDeferredCanvas::skew(SkScalar sx, SkScalar sy) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000246 drawingCanvas()->skew(sx, sy);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000247 return this->INHERITED::skew(sx, sy);
junov@google.com4370aed2012-01-18 16:21:08 +0000248}
249
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000250bool SkDeferredCanvas::concat(const SkMatrix& matrix) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000251 drawingCanvas()->concat(matrix);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000252 return this->INHERITED::concat(matrix);
junov@google.com4370aed2012-01-18 16:21:08 +0000253}
254
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000255void SkDeferredCanvas::setMatrix(const SkMatrix& matrix) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000256 drawingCanvas()->setMatrix(matrix);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000257 this->INHERITED::setMatrix(matrix);
junov@google.com4370aed2012-01-18 16:21:08 +0000258}
259
260bool SkDeferredCanvas::clipRect(const SkRect& rect,
261 SkRegion::Op op,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000262 bool doAntiAlias) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000263 drawingCanvas()->clipRect(rect, op, doAntiAlias);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000264 return this->INHERITED::clipRect(rect, op, doAntiAlias);
junov@google.com4370aed2012-01-18 16:21:08 +0000265}
266
267bool SkDeferredCanvas::clipPath(const SkPath& path,
268 SkRegion::Op op,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000269 bool doAntiAlias) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000270 drawingCanvas()->clipPath(path, op, doAntiAlias);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000271 return this->INHERITED::clipPath(path, op, doAntiAlias);
junov@google.com4370aed2012-01-18 16:21:08 +0000272}
273
274bool SkDeferredCanvas::clipRegion(const SkRegion& deviceRgn,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000275 SkRegion::Op op) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000276 drawingCanvas()->clipRegion(deviceRgn, op);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000277 return this->INHERITED::clipRegion(deviceRgn, op);
junov@google.com4370aed2012-01-18 16:21:08 +0000278}
279
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000280void SkDeferredCanvas::clear(SkColor color) {
junov@google.com4370aed2012-01-18 16:21:08 +0000281 // purge pending commands
282 if (fDeferredDrawing) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000283 getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000284 }
285
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000286 drawingCanvas()->clear(color);
junov@google.com4370aed2012-01-18 16:21:08 +0000287}
288
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000289void SkDeferredCanvas::drawPaint(const SkPaint& paint) {
290 if (fDeferredDrawing && isFullFrame(NULL, &paint) &&
291 isPaintOpaque(&paint)) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000292 getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000293 }
294
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000295 drawingCanvas()->drawPaint(paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000296}
297
298void SkDeferredCanvas::drawPoints(PointMode mode, size_t count,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000299 const SkPoint pts[], const SkPaint& paint) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000300 drawingCanvas()->drawPoints(mode, count, pts, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000301}
302
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000303void SkDeferredCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
304 if (fDeferredDrawing && isFullFrame(&rect, &paint) &&
305 isPaintOpaque(&paint)) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000306 getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000307 }
308
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000309 drawingCanvas()->drawRect(rect, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000310}
311
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000312void SkDeferredCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000313 drawingCanvas()->drawPath(path, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000314}
315
316void SkDeferredCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000317 SkScalar top, const SkPaint* paint) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000318 SkRect bitmapRect = SkRect::MakeXYWH(left, top,
319 SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height()));
junov@google.com4370aed2012-01-18 16:21:08 +0000320 if (fDeferredDrawing &&
321 isFullFrame(&bitmapRect, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000322 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000323 getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000324 }
325
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000326 drawingCanvas()->drawBitmap(bitmap, left, top, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000327 flushIfNeeded(bitmap);
328}
329
330void SkDeferredCanvas::drawBitmapRect(const SkBitmap& bitmap,
331 const SkIRect* src,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000332 const SkRect& dst,
333 const SkPaint* paint) {
junov@google.com4370aed2012-01-18 16:21:08 +0000334 if (fDeferredDrawing &&
335 isFullFrame(&dst, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000336 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000337 getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000338 }
339
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000340 drawingCanvas()->drawBitmapRect(bitmap, src,
junov@google.com4370aed2012-01-18 16:21:08 +0000341 dst, paint);
342 flushIfNeeded(bitmap);
343}
344
345
346void SkDeferredCanvas::drawBitmapMatrix(const SkBitmap& bitmap,
347 const SkMatrix& m,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000348 const SkPaint* paint) {
junov@google.com4370aed2012-01-18 16:21:08 +0000349 // TODO: reset recording canvas if paint+bitmap is opaque and clip rect
350 // covers canvas entirely and transformed bitmap covers canvas entirely
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000351 drawingCanvas()->drawBitmapMatrix(bitmap, m, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000352 flushIfNeeded(bitmap);
353}
354
355void SkDeferredCanvas::drawBitmapNine(const SkBitmap& bitmap,
356 const SkIRect& center, const SkRect& dst,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000357 const SkPaint* paint) {
junov@google.com4370aed2012-01-18 16:21:08 +0000358 // TODO: reset recording canvas if paint+bitmap is opaque and clip rect
359 // covers canvas entirely and dst covers canvas entirely
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000360 drawingCanvas()->drawBitmapNine(bitmap, center,
junov@google.com4370aed2012-01-18 16:21:08 +0000361 dst, paint);
362 flushIfNeeded(bitmap);
363}
364
365void SkDeferredCanvas::drawSprite(const SkBitmap& bitmap, int left, int top,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000366 const SkPaint* paint) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000367 SkRect bitmapRect = SkRect::MakeXYWH(
368 SkIntToScalar(left),
369 SkIntToScalar(top),
370 SkIntToScalar(bitmap.width()),
371 SkIntToScalar(bitmap.height()));
junov@google.com4370aed2012-01-18 16:21:08 +0000372 if (fDeferredDrawing &&
373 isFullFrame(&bitmapRect, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000374 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000375 getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000376 }
377
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000378 drawingCanvas()->drawSprite(bitmap, left, top,
junov@google.com4370aed2012-01-18 16:21:08 +0000379 paint);
380 flushIfNeeded(bitmap);
381}
382
383void SkDeferredCanvas::drawText(const void* text, size_t byteLength,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000384 SkScalar x, SkScalar y, const SkPaint& paint) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000385 drawingCanvas()->drawText(text, byteLength, x, y, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000386}
387
388void SkDeferredCanvas::drawPosText(const void* text, size_t byteLength,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000389 const SkPoint pos[], const SkPaint& paint) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000390 drawingCanvas()->drawPosText(text, byteLength, pos, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000391}
392
393void SkDeferredCanvas::drawPosTextH(const void* text, size_t byteLength,
394 const SkScalar xpos[], SkScalar constY,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000395 const SkPaint& paint) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000396 drawingCanvas()->drawPosTextH(text, byteLength, xpos, constY, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000397}
398
399void SkDeferredCanvas::drawTextOnPath(const void* text, size_t byteLength,
400 const SkPath& path,
401 const SkMatrix* matrix,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000402 const SkPaint& paint) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000403 drawingCanvas()->drawTextOnPath(text, byteLength,
junov@google.com4370aed2012-01-18 16:21:08 +0000404 path, matrix,
405 paint);
406}
407
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000408void SkDeferredCanvas::drawPicture(SkPicture& picture) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000409 drawingCanvas()->drawPicture(picture);
junov@google.com4370aed2012-01-18 16:21:08 +0000410}
411
412void SkDeferredCanvas::drawVertices(VertexMode vmode, int vertexCount,
413 const SkPoint vertices[],
414 const SkPoint texs[],
415 const SkColor colors[], SkXfermode* xmode,
416 const uint16_t indices[], int indexCount,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000417 const SkPaint& paint) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000418 drawingCanvas()->drawVertices(vmode, vertexCount,
junov@google.com4370aed2012-01-18 16:21:08 +0000419 vertices, texs,
420 colors, xmode,
421 indices, indexCount,
422 paint);
423}
424
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000425SkBounder* SkDeferredCanvas::setBounder(SkBounder* bounder) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000426 drawingCanvas()->setBounder(bounder);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000427 return INHERITED::setBounder(bounder);
junov@google.com4370aed2012-01-18 16:21:08 +0000428}
429
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000430SkDrawFilter* SkDeferredCanvas::setDrawFilter(SkDrawFilter* filter) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000431 drawingCanvas()->setDrawFilter(filter);
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000432 return INHERITED::setDrawFilter(filter);
junov@google.com4370aed2012-01-18 16:21:08 +0000433}
434
435SkCanvas* SkDeferredCanvas::canvasForDrawIter() {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000436 return drawingCanvas();
junov@google.com4370aed2012-01-18 16:21:08 +0000437}
438
439// SkDeferredCanvas::DeferredDevice
440//------------------------------------
441
442SkDeferredCanvas::DeferredDevice::DeferredDevice(
443 SkDevice* immediateDevice, DeviceContext* deviceContext) :
444 SkDevice(SkBitmap::kNo_Config, immediateDevice->width(),
445 immediateDevice->height(), immediateDevice->isOpaque())
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000446 , fFreshFrame(true) {
447
junov@google.com4370aed2012-01-18 16:21:08 +0000448 fDeviceContext = deviceContext;
449 SkSafeRef(fDeviceContext);
450 fImmediateDevice = immediateDevice; // ref counted via fImmediateCanvas
451 fImmediateCanvas = SkNEW_ARGS(SkCanvas, (fImmediateDevice));
junov@google.com4370aed2012-01-18 16:21:08 +0000452 fRecordingCanvas = fPicture.beginRecording(fImmediateDevice->width(),
junov@chromium.org4866cc02012-06-01 21:23:07 +0000453 fImmediateDevice->height(),
454 SkPicture::kFlattenMutableNonTexturePixelRefs_RecordingFlag);
junov@google.com4370aed2012-01-18 16:21:08 +0000455}
456
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000457SkDeferredCanvas::DeferredDevice::~DeferredDevice() {
junov@google.com4370aed2012-01-18 16:21:08 +0000458 SkSafeUnref(fImmediateCanvas);
459 SkSafeUnref(fDeviceContext);
460}
461
462void SkDeferredCanvas::DeferredDevice::setDeviceContext(
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000463 DeviceContext* deviceContext) {
junov@google.com4370aed2012-01-18 16:21:08 +0000464 SkRefCnt_SafeAssign(fDeviceContext, deviceContext);
465}
466
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000467void SkDeferredCanvas::DeferredDevice::contentsCleared() {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000468 if (!fRecordingCanvas->isDrawingToLayer()) {
469 fFreshFrame = true;
junov@google.com4370aed2012-01-18 16:21:08 +0000470
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000471 // TODO: find a way to transfer the state stack and layers
472 // to the new recording canvas. For now, purging only works
473 // with an empty stack.
474 if (fRecordingCanvas->getSaveCount() == 0) {
junov@google.com4370aed2012-01-18 16:21:08 +0000475
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000476 // Save state that is trashed by the purge
477 SkDrawFilter* drawFilter = fRecordingCanvas->getDrawFilter();
478 SkSafeRef(drawFilter); // So that it survives the purge
479 SkMatrix matrix = fRecordingCanvas->getTotalMatrix();
480 SkRegion clipRegion = fRecordingCanvas->getTotalClip();
junov@google.com4370aed2012-01-18 16:21:08 +0000481
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000482 // beginRecording creates a new recording canvas and discards the
483 // old one, hence purging deferred draw ops.
484 fRecordingCanvas = fPicture.beginRecording(
485 fImmediateDevice->width(),
junov@chromium.org4866cc02012-06-01 21:23:07 +0000486 fImmediateDevice->height(),
487 SkPicture::kFlattenMutableNonTexturePixelRefs_RecordingFlag);
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000488
489 // Restore pre-purge state
490 if (!clipRegion.isEmpty()) {
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000491 fRecordingCanvas->clipRegion(clipRegion,
492 SkRegion::kReplace_Op);
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000493 }
494 if (!matrix.isIdentity()) {
495 fRecordingCanvas->setMatrix(matrix);
496 }
497 if (drawFilter) {
498 fRecordingCanvas->setDrawFilter(drawFilter)->unref();
499 }
500 }
junov@google.com4370aed2012-01-18 16:21:08 +0000501 }
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000502}
503
504bool SkDeferredCanvas::DeferredDevice::isFreshFrame() {
505 bool ret = fFreshFrame;
506 fFreshFrame = false;
507 return ret;
junov@google.com4370aed2012-01-18 16:21:08 +0000508}
509
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000510void SkDeferredCanvas::DeferredDevice::flushPending() {
junov@chromium.org4866cc02012-06-01 21:23:07 +0000511 if (!fPicture.hasRecorded()) {
512 return;
513 }
junov@google.com4370aed2012-01-18 16:21:08 +0000514 if (fDeviceContext) {
515 fDeviceContext->prepareForDraw();
516 }
517 fPicture.draw(fImmediateCanvas);
518 fRecordingCanvas = fPicture.beginRecording(fImmediateDevice->width(),
junov@chromium.org4866cc02012-06-01 21:23:07 +0000519 fImmediateDevice->height(),
520 SkPicture::kFlattenMutableNonTexturePixelRefs_RecordingFlag);
junov@google.com4370aed2012-01-18 16:21:08 +0000521}
522
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000523void SkDeferredCanvas::DeferredDevice::flush() {
junov@google.com4370aed2012-01-18 16:21:08 +0000524 flushPending();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000525 fImmediateCanvas->flush();
junov@google.com4370aed2012-01-18 16:21:08 +0000526}
527
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000528void SkDeferredCanvas::DeferredDevice::flushIfNeeded(const SkBitmap& bitmap) {
junov@chromium.org4866cc02012-06-01 21:23:07 +0000529 if (bitmap.isImmutable() || fPicture.willFlattenPixelsOnRecord(bitmap)) {
530 return; // safe to defer.
junov@google.com4370aed2012-01-18 16:21:08 +0000531 }
532
533 // For now, drawing a writable bitmap triggers a flush
534 // TODO: implement read-only semantics and auto buffer duplication on write
535 // in SkBitmap/SkPixelRef, which will make deferral possible in this case.
536 flushPending();
537}
538
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000539uint32_t SkDeferredCanvas::DeferredDevice::getDeviceCapabilities() {
junov@google.com4370aed2012-01-18 16:21:08 +0000540 return fImmediateDevice->getDeviceCapabilities();
541}
542
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000543int SkDeferredCanvas::DeferredDevice::width() const {
junov@google.com4370aed2012-01-18 16:21:08 +0000544 return fImmediateDevice->width();
545}
546
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000547int SkDeferredCanvas::DeferredDevice::height() const {
junov@google.com4370aed2012-01-18 16:21:08 +0000548 return fImmediateDevice->height();
549}
550
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000551SkGpuRenderTarget* SkDeferredCanvas::DeferredDevice::accessRenderTarget() {
junov@google.com4370aed2012-01-18 16:21:08 +0000552 flushPending();
553 return fImmediateDevice->accessRenderTarget();
554}
555
556void SkDeferredCanvas::DeferredDevice::writePixels(const SkBitmap& bitmap,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000557 int x, int y, SkCanvas::Config8888 config8888) {
558
junov@google.com4370aed2012-01-18 16:21:08 +0000559 if (x <= 0 && y <= 0 && (x + bitmap.width()) >= width() &&
560 (y + bitmap.height()) >= height()) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000561 contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000562 }
563
564 if (SkBitmap::kARGB_8888_Config == bitmap.config() &&
565 SkCanvas::kNative_Premul_Config8888 != config8888 &&
566 kPMColorAlias != config8888) {
567 //Special case config: no deferral
568 flushPending();
569 fImmediateDevice->writePixels(bitmap, x, y, config8888);
570 }
571
572 SkPaint paint;
573 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
574 fRecordingCanvas->drawSprite(bitmap, x, y, &paint);
575 flushIfNeeded(bitmap);
576}
577
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000578const SkBitmap& SkDeferredCanvas::DeferredDevice::onAccessBitmap(SkBitmap*) {
junov@google.com4370aed2012-01-18 16:21:08 +0000579 flushPending();
junov@chromium.org1f9767c2012-02-07 16:27:57 +0000580 return fImmediateDevice->accessBitmap(false);
junov@google.com4370aed2012-01-18 16:21:08 +0000581}
582
583SkDevice* SkDeferredCanvas::DeferredDevice::onCreateCompatibleDevice(
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000584 SkBitmap::Config config, int width, int height, bool isOpaque,
585 Usage usage) {
586
junov@google.com4370aed2012-01-18 16:21:08 +0000587 // Save layer usage not supported, and not required by SkDeferredCanvas.
588 SkASSERT(usage != kSaveLayer_Usage);
589 // Create a compatible non-deferred device.
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000590 SkDevice* compatibleDevice =
591 fImmediateDevice->createCompatibleDevice(config, width, height,
592 isOpaque);
junov@google.com4370aed2012-01-18 16:21:08 +0000593 return SkNEW_ARGS(DeferredDevice, (compatibleDevice, fDeviceContext));
594}
595
596bool SkDeferredCanvas::DeferredDevice::onReadPixels(
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000597 const SkBitmap& bitmap, int x, int y, SkCanvas::Config8888 config8888) {
junov@google.com4370aed2012-01-18 16:21:08 +0000598 flushPending();
599 return fImmediateCanvas->readPixels(const_cast<SkBitmap*>(&bitmap),
600 x, y, config8888);
601}