blob: 1753d649b1e8a11500b0d20a3b85b94afa8c529a [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.orgfeba6892012-02-28 15:02:06 +000098 fDeferredDrawing = true;
99 fDrawingCanvas = NULL;
junov@google.com4370aed2012-01-18 16:21:08 +0000100}
101
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000102void SkDeferredCanvas::validate() const {
junov@google.com4370aed2012-01-18 16:21:08 +0000103 SkASSERT(getDevice());
junov@google.com4370aed2012-01-18 16:21:08 +0000104}
105
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000106void SkDeferredCanvas::flushIfNeeded(const SkBitmap& bitmap) {
junov@google.com4370aed2012-01-18 16:21:08 +0000107 validate();
108 if (fDeferredDrawing) {
109 getDeferredDevice()->flushIfNeeded(bitmap);
110 }
111}
112
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000113SkDeferredCanvas::DeferredDevice* SkDeferredCanvas::getDeferredDevice() const {
junov@google.com4370aed2012-01-18 16:21:08 +0000114 return static_cast<SkDeferredCanvas::DeferredDevice*>(getDevice());
115}
116
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000117void SkDeferredCanvas::setDeferredDrawing(bool val) {
junov@google.com4370aed2012-01-18 16:21:08 +0000118 validate(); // Must set device before calling this method
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000119 SkASSERT(fDrawingCanvas->getSaveCount() == 1);
junov@google.com4370aed2012-01-18 16:21:08 +0000120 if (val != fDeferredDrawing) {
121 if (fDeferredDrawing) {
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000122 // Going live.
junov@google.com4370aed2012-01-18 16:21:08 +0000123 getDeferredDevice()->flushPending();
124 }
125 fDeferredDrawing = val;
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000126 fDrawingCanvas = val ?
127 getDeferredDevice()->recordingCanvas() :
128 getDeferredDevice()->immediateCanvas();
junov@google.com4370aed2012-01-18 16:21:08 +0000129 }
130}
131
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000132SkDeferredCanvas::~SkDeferredCanvas() {
junov@google.com4370aed2012-01-18 16:21:08 +0000133}
134
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000135SkDevice* SkDeferredCanvas::setDevice(SkDevice* device) {
junov@google.com4370aed2012-01-18 16:21:08 +0000136 INHERITED::setDevice(SkNEW_ARGS(DeferredDevice, (device)))->unref();
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000137 fDrawingCanvas = fDeferredDrawing ?
138 getDeferredDevice()->recordingCanvas() :
139 getDeferredDevice()->immediateCanvas();
junov@google.com4370aed2012-01-18 16:21:08 +0000140 return device;
141}
142
143SkDeferredCanvas::DeviceContext* SkDeferredCanvas::setDeviceContext(
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000144 DeviceContext* deviceContext) {
145
junov@google.com4370aed2012-01-18 16:21:08 +0000146 DeferredDevice* deferredDevice = getDeferredDevice();
147 SkASSERT(deferredDevice);
148 if (deferredDevice) {
149 deferredDevice->setDeviceContext(deviceContext);
150 }
151 return deviceContext;
152}
153
154bool SkDeferredCanvas::isFullFrame(const SkRect* rect,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000155 const SkPaint* paint) const {
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000156 SkCanvas* canvas = fDrawingCanvas;
junov@google.com4370aed2012-01-18 16:21:08 +0000157 SkISize canvasSize = getDeviceSize();
158 if (rect) {
159 if (!canvas->getTotalMatrix().rectStaysRect()) {
160 return false; // conservative
161 }
162
163 SkRect transformedRect;
164 canvas->getTotalMatrix().mapRect(&transformedRect, *rect);
165
166 if (paint) {
167 SkPaint::Style paintStyle = paint->getStyle();
168 if (!(paintStyle == SkPaint::kFill_Style ||
169 paintStyle == SkPaint::kStrokeAndFill_Style)) {
170 return false;
171 }
172 if (paint->getMaskFilter() || paint->getLooper()
173 || paint->getPathEffect() || paint->getImageFilter()) {
174 return false; // conservative
175 }
176 }
177
178 // The following test holds with AA enabled, and is conservative
179 // by a 0.5 pixel margin with AA disabled
junov@chromium.orgb1e218e2012-02-13 22:27:58 +0000180 if (transformedRect.fLeft > SkIntToScalar(0) ||
181 transformedRect.fTop > SkIntToScalar(0) ||
182 transformedRect.fRight < SkIntToScalar(canvasSize.fWidth) ||
183 transformedRect.fBottom < SkIntToScalar(canvasSize.fHeight)) {
junov@google.com4370aed2012-01-18 16:21:08 +0000184 return false;
185 }
186 }
187
188 switch (canvas->getClipType()) {
189 case SkCanvas::kRect_ClipType :
190 {
191 SkIRect bounds;
192 canvas->getClipDeviceBounds(&bounds);
193 if (bounds.fLeft > 0 || bounds.fTop > 0 ||
194 bounds.fRight < canvasSize.fWidth ||
195 bounds.fBottom < canvasSize.fHeight)
196 return false;
197 }
198 break;
199 case SkCanvas::kComplex_ClipType :
200 return false; // conservative
201 case SkCanvas::kEmpty_ClipType:
202 default:
203 break;
204 };
205
206 return true;
207}
208
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000209int SkDeferredCanvas::save(SaveFlags flags) {
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000210 fDrawingCanvas->save(flags);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000211 return this->INHERITED::save(flags);
junov@google.com4370aed2012-01-18 16:21:08 +0000212}
213
214int SkDeferredCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000215 SaveFlags flags) {
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000216 fDrawingCanvas->saveLayer(bounds, paint, flags);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000217 int count = this->INHERITED::save(flags);
218 this->clipRectBounds(bounds, flags, NULL);
219 return count;
junov@google.com4370aed2012-01-18 16:21:08 +0000220}
221
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000222void SkDeferredCanvas::restore() {
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000223 fDrawingCanvas->restore();
junov@chromium.orga907ac32012-02-24 21:54:07 +0000224 this->INHERITED::restore();
junov@google.com4370aed2012-01-18 16:21:08 +0000225}
226
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000227bool SkDeferredCanvas::isDrawingToLayer() const {
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000228 return fDrawingCanvas->isDrawingToLayer();
junov@google.com4370aed2012-01-18 16:21:08 +0000229}
230
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000231bool SkDeferredCanvas::translate(SkScalar dx, SkScalar dy) {
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000232 fDrawingCanvas->translate(dx, dy);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000233 return this->INHERITED::translate(dx, dy);
junov@google.com4370aed2012-01-18 16:21:08 +0000234}
235
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000236bool SkDeferredCanvas::scale(SkScalar sx, SkScalar sy) {
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000237 fDrawingCanvas->scale(sx, sy);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000238 return this->INHERITED::scale(sx, sy);
junov@google.com4370aed2012-01-18 16:21:08 +0000239}
240
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000241bool SkDeferredCanvas::rotate(SkScalar degrees) {
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000242 fDrawingCanvas->rotate(degrees);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000243 return this->INHERITED::rotate(degrees);
junov@google.com4370aed2012-01-18 16:21:08 +0000244}
245
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000246bool SkDeferredCanvas::skew(SkScalar sx, SkScalar sy) {
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000247 fDrawingCanvas->skew(sx, sy);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000248 return this->INHERITED::skew(sx, sy);
junov@google.com4370aed2012-01-18 16:21:08 +0000249}
250
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000251bool SkDeferredCanvas::concat(const SkMatrix& matrix) {
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000252 fDrawingCanvas->concat(matrix);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000253 return this->INHERITED::concat(matrix);
junov@google.com4370aed2012-01-18 16:21:08 +0000254}
255
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000256void SkDeferredCanvas::setMatrix(const SkMatrix& matrix) {
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000257 fDrawingCanvas->setMatrix(matrix);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000258 this->INHERITED::setMatrix(matrix);
junov@google.com4370aed2012-01-18 16:21:08 +0000259}
260
261bool SkDeferredCanvas::clipRect(const SkRect& rect,
262 SkRegion::Op op,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000263 bool doAntiAlias) {
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000264 fDrawingCanvas->clipRect(rect, op, doAntiAlias);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000265 return this->INHERITED::clipRect(rect, op, doAntiAlias);
junov@google.com4370aed2012-01-18 16:21:08 +0000266}
267
268bool SkDeferredCanvas::clipPath(const SkPath& path,
269 SkRegion::Op op,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000270 bool doAntiAlias) {
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000271 fDrawingCanvas->clipPath(path, op, doAntiAlias);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000272 return this->INHERITED::clipPath(path, op, doAntiAlias);
junov@google.com4370aed2012-01-18 16:21:08 +0000273}
274
275bool SkDeferredCanvas::clipRegion(const SkRegion& deviceRgn,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000276 SkRegion::Op op) {
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000277 fDrawingCanvas->clipRegion(deviceRgn, op);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000278 return this->INHERITED::clipRegion(deviceRgn, op);
junov@google.com4370aed2012-01-18 16:21:08 +0000279}
280
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000281void SkDeferredCanvas::clear(SkColor color) {
junov@google.com4370aed2012-01-18 16:21:08 +0000282 // purge pending commands
283 if (fDeferredDrawing) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000284 getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000285 }
286
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000287 fDrawingCanvas->clear(color);
junov@google.com4370aed2012-01-18 16:21:08 +0000288}
289
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000290void SkDeferredCanvas::drawPaint(const SkPaint& paint) {
291 if (fDeferredDrawing && isFullFrame(NULL, &paint) &&
292 isPaintOpaque(&paint)) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000293 getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000294 }
295
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000296 fDrawingCanvas->drawPaint(paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000297}
298
299void SkDeferredCanvas::drawPoints(PointMode mode, size_t count,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000300 const SkPoint pts[], const SkPaint& paint) {
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000301 fDrawingCanvas->drawPoints(mode, count, pts, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000302}
303
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000304void SkDeferredCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
305 if (fDeferredDrawing && isFullFrame(&rect, &paint) &&
306 isPaintOpaque(&paint)) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000307 getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000308 }
309
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000310 fDrawingCanvas->drawRect(rect, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000311}
312
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000313void SkDeferredCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000314 fDrawingCanvas->drawPath(path, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000315}
316
317void SkDeferredCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000318 SkScalar top, const SkPaint* paint) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000319 SkRect bitmapRect = SkRect::MakeXYWH(left, top,
320 SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height()));
junov@google.com4370aed2012-01-18 16:21:08 +0000321 if (fDeferredDrawing &&
322 isFullFrame(&bitmapRect, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000323 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000324 getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000325 }
326
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000327 fDrawingCanvas->drawBitmap(bitmap, left, top, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000328 flushIfNeeded(bitmap);
329}
330
331void SkDeferredCanvas::drawBitmapRect(const SkBitmap& bitmap,
332 const SkIRect* src,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000333 const SkRect& dst,
334 const SkPaint* paint) {
junov@google.com4370aed2012-01-18 16:21:08 +0000335 if (fDeferredDrawing &&
336 isFullFrame(&dst, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000337 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000338 getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000339 }
340
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000341 fDrawingCanvas->drawBitmapRect(bitmap, src,
junov@google.com4370aed2012-01-18 16:21:08 +0000342 dst, paint);
343 flushIfNeeded(bitmap);
344}
345
346
347void SkDeferredCanvas::drawBitmapMatrix(const SkBitmap& bitmap,
348 const SkMatrix& m,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000349 const SkPaint* paint) {
junov@google.com4370aed2012-01-18 16:21:08 +0000350 // TODO: reset recording canvas if paint+bitmap is opaque and clip rect
351 // covers canvas entirely and transformed bitmap covers canvas entirely
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000352 fDrawingCanvas->drawBitmapMatrix(bitmap, m, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000353 flushIfNeeded(bitmap);
354}
355
356void SkDeferredCanvas::drawBitmapNine(const SkBitmap& bitmap,
357 const SkIRect& center, const SkRect& dst,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000358 const SkPaint* paint) {
junov@google.com4370aed2012-01-18 16:21:08 +0000359 // TODO: reset recording canvas if paint+bitmap is opaque and clip rect
360 // covers canvas entirely and dst covers canvas entirely
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000361 fDrawingCanvas->drawBitmapNine(bitmap, center,
junov@google.com4370aed2012-01-18 16:21:08 +0000362 dst, paint);
363 flushIfNeeded(bitmap);
364}
365
366void SkDeferredCanvas::drawSprite(const SkBitmap& bitmap, int left, int top,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000367 const SkPaint* paint) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000368 SkRect bitmapRect = SkRect::MakeXYWH(
369 SkIntToScalar(left),
370 SkIntToScalar(top),
371 SkIntToScalar(bitmap.width()),
372 SkIntToScalar(bitmap.height()));
junov@google.com4370aed2012-01-18 16:21:08 +0000373 if (fDeferredDrawing &&
374 isFullFrame(&bitmapRect, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000375 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000376 getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000377 }
378
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000379 fDrawingCanvas->drawSprite(bitmap, left, top,
junov@google.com4370aed2012-01-18 16:21:08 +0000380 paint);
381 flushIfNeeded(bitmap);
382}
383
384void SkDeferredCanvas::drawText(const void* text, size_t byteLength,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000385 SkScalar x, SkScalar y, const SkPaint& paint) {
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000386 fDrawingCanvas->drawText(text, byteLength, x, y, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000387}
388
389void SkDeferredCanvas::drawPosText(const void* text, size_t byteLength,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000390 const SkPoint pos[], const SkPaint& paint) {
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000391 fDrawingCanvas->drawPosText(text, byteLength, pos, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000392}
393
394void SkDeferredCanvas::drawPosTextH(const void* text, size_t byteLength,
395 const SkScalar xpos[], SkScalar constY,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000396 const SkPaint& paint) {
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000397 fDrawingCanvas->drawPosTextH(text, byteLength, xpos, constY, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000398}
399
400void SkDeferredCanvas::drawTextOnPath(const void* text, size_t byteLength,
401 const SkPath& path,
402 const SkMatrix* matrix,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000403 const SkPaint& paint) {
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000404 fDrawingCanvas->drawTextOnPath(text, byteLength,
junov@google.com4370aed2012-01-18 16:21:08 +0000405 path, matrix,
406 paint);
407}
408
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000409void SkDeferredCanvas::drawPicture(SkPicture& picture) {
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000410 fDrawingCanvas->drawPicture(picture);
junov@google.com4370aed2012-01-18 16:21:08 +0000411}
412
413void SkDeferredCanvas::drawVertices(VertexMode vmode, int vertexCount,
414 const SkPoint vertices[],
415 const SkPoint texs[],
416 const SkColor colors[], SkXfermode* xmode,
417 const uint16_t indices[], int indexCount,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000418 const SkPaint& paint) {
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000419 fDrawingCanvas->drawVertices(vmode, vertexCount,
junov@google.com4370aed2012-01-18 16:21:08 +0000420 vertices, texs,
421 colors, xmode,
422 indices, indexCount,
423 paint);
424}
425
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000426SkBounder* SkDeferredCanvas::setBounder(SkBounder* bounder) {
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000427 fDrawingCanvas->setBounder(bounder);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000428 return INHERITED::setBounder(bounder);
junov@google.com4370aed2012-01-18 16:21:08 +0000429}
430
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000431SkDrawFilter* SkDeferredCanvas::setDrawFilter(SkDrawFilter* filter) {
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000432 fDrawingCanvas->setDrawFilter(filter);
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000433 return INHERITED::setDrawFilter(filter);
junov@google.com4370aed2012-01-18 16:21:08 +0000434}
435
436SkCanvas* SkDeferredCanvas::canvasForDrawIter() {
junov@chromium.orgfeba6892012-02-28 15:02:06 +0000437 return fDrawingCanvas;
junov@google.com4370aed2012-01-18 16:21:08 +0000438}
439
440// SkDeferredCanvas::DeferredDevice
441//------------------------------------
442
443SkDeferredCanvas::DeferredDevice::DeferredDevice(
444 SkDevice* immediateDevice, DeviceContext* deviceContext) :
445 SkDevice(SkBitmap::kNo_Config, immediateDevice->width(),
446 immediateDevice->height(), immediateDevice->isOpaque())
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000447 , fFreshFrame(true) {
448
junov@google.com4370aed2012-01-18 16:21:08 +0000449 fDeviceContext = deviceContext;
450 SkSafeRef(fDeviceContext);
451 fImmediateDevice = immediateDevice; // ref counted via fImmediateCanvas
452 fImmediateCanvas = SkNEW_ARGS(SkCanvas, (fImmediateDevice));
junov@google.com4370aed2012-01-18 16:21:08 +0000453 fRecordingCanvas = fPicture.beginRecording(fImmediateDevice->width(),
junov@chromium.orga907ac32012-02-24 21:54:07 +0000454 fImmediateDevice->height(), 0);
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.orga907ac32012-02-24 21:54:07 +0000486 fImmediateDevice->height(), 0);
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000487
488 // Restore pre-purge state
489 if (!clipRegion.isEmpty()) {
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000490 fRecordingCanvas->clipRegion(clipRegion,
491 SkRegion::kReplace_Op);
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000492 }
493 if (!matrix.isIdentity()) {
494 fRecordingCanvas->setMatrix(matrix);
495 }
496 if (drawFilter) {
497 fRecordingCanvas->setDrawFilter(drawFilter)->unref();
498 }
499 }
junov@google.com4370aed2012-01-18 16:21:08 +0000500 }
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000501}
502
503bool SkDeferredCanvas::DeferredDevice::isFreshFrame() {
504 bool ret = fFreshFrame;
505 fFreshFrame = false;
506 return ret;
junov@google.com4370aed2012-01-18 16:21:08 +0000507}
508
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000509void SkDeferredCanvas::DeferredDevice::flushPending() {
junov@google.com4370aed2012-01-18 16:21:08 +0000510 if (fDeviceContext) {
511 fDeviceContext->prepareForDraw();
512 }
513 fPicture.draw(fImmediateCanvas);
514 fRecordingCanvas = fPicture.beginRecording(fImmediateDevice->width(),
junov@chromium.orga907ac32012-02-24 21:54:07 +0000515 fImmediateDevice->height(), 0);
junov@google.com4370aed2012-01-18 16:21:08 +0000516}
517
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000518void SkDeferredCanvas::DeferredDevice::flush() {
junov@google.com4370aed2012-01-18 16:21:08 +0000519 flushPending();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000520 fImmediateCanvas->flush();
junov@google.com4370aed2012-01-18 16:21:08 +0000521}
522
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000523void SkDeferredCanvas::DeferredDevice::flushIfNeeded(const SkBitmap& bitmap) {
junov@google.com4370aed2012-01-18 16:21:08 +0000524 if (bitmap.isImmutable()) {
525 return; // safe to deffer without registering a dependency
526 }
527
528 // For now, drawing a writable bitmap triggers a flush
529 // TODO: implement read-only semantics and auto buffer duplication on write
530 // in SkBitmap/SkPixelRef, which will make deferral possible in this case.
531 flushPending();
532}
533
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000534uint32_t SkDeferredCanvas::DeferredDevice::getDeviceCapabilities() {
junov@google.com4370aed2012-01-18 16:21:08 +0000535 return fImmediateDevice->getDeviceCapabilities();
536}
537
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000538int SkDeferredCanvas::DeferredDevice::width() const {
junov@google.com4370aed2012-01-18 16:21:08 +0000539 return fImmediateDevice->width();
540}
541
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000542int SkDeferredCanvas::DeferredDevice::height() const {
junov@google.com4370aed2012-01-18 16:21:08 +0000543 return fImmediateDevice->height();
544}
545
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000546SkGpuRenderTarget* SkDeferredCanvas::DeferredDevice::accessRenderTarget() {
junov@google.com4370aed2012-01-18 16:21:08 +0000547 flushPending();
548 return fImmediateDevice->accessRenderTarget();
549}
550
551void SkDeferredCanvas::DeferredDevice::writePixels(const SkBitmap& bitmap,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000552 int x, int y, SkCanvas::Config8888 config8888) {
553
junov@google.com4370aed2012-01-18 16:21:08 +0000554 if (x <= 0 && y <= 0 && (x + bitmap.width()) >= width() &&
555 (y + bitmap.height()) >= height()) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000556 contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000557 }
558
559 if (SkBitmap::kARGB_8888_Config == bitmap.config() &&
560 SkCanvas::kNative_Premul_Config8888 != config8888 &&
561 kPMColorAlias != config8888) {
562 //Special case config: no deferral
563 flushPending();
564 fImmediateDevice->writePixels(bitmap, x, y, config8888);
565 }
566
567 SkPaint paint;
568 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
569 fRecordingCanvas->drawSprite(bitmap, x, y, &paint);
570 flushIfNeeded(bitmap);
571}
572
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000573const SkBitmap& SkDeferredCanvas::DeferredDevice::onAccessBitmap(SkBitmap*) {
junov@google.com4370aed2012-01-18 16:21:08 +0000574 flushPending();
junov@chromium.org1f9767c2012-02-07 16:27:57 +0000575 return fImmediateDevice->accessBitmap(false);
junov@google.com4370aed2012-01-18 16:21:08 +0000576}
577
578SkDevice* SkDeferredCanvas::DeferredDevice::onCreateCompatibleDevice(
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000579 SkBitmap::Config config, int width, int height, bool isOpaque,
580 Usage usage) {
581
junov@google.com4370aed2012-01-18 16:21:08 +0000582 // Save layer usage not supported, and not required by SkDeferredCanvas.
583 SkASSERT(usage != kSaveLayer_Usage);
584 // Create a compatible non-deferred device.
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000585 SkDevice* compatibleDevice =
586 fImmediateDevice->createCompatibleDevice(config, width, height,
587 isOpaque);
junov@google.com4370aed2012-01-18 16:21:08 +0000588 return SkNEW_ARGS(DeferredDevice, (compatibleDevice, fDeviceContext));
589}
590
591bool SkDeferredCanvas::DeferredDevice::onReadPixels(
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000592 const SkBitmap& bitmap, int x, int y, SkCanvas::Config8888 config8888) {
junov@google.com4370aed2012-01-18 16:21:08 +0000593 flushPending();
594 return fImmediateCanvas->readPixels(const_cast<SkBitmap*>(&bitmap),
595 x, y, config8888);
596}