blob: 12543920a36ff1d6c10e125f990fb1e501e53c4b [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.org87f982c2012-02-23 21:34:34 +000018bool isPaintOpaque(const SkPaint* paint, const SkBitmap* bmpReplacesShader = NULL) {
junov@google.com4370aed2012-01-18 16:21:08 +000019 // TODO: SkXfermode should have a virtual isOpaque method, which would
20 // make it possible to test modes that do not have a Coeff representation.
junov@chromium.org87f982c2012-02-23 21:34:34 +000021
22 if (!paint) {
23 return bmpReplacesShader ? bmpReplacesShader->isOpaque() : true;
24 }
25
junov@google.com4370aed2012-01-18 16:21:08 +000026 SkXfermode::Coeff srcCoeff, dstCoeff;
junov@chromium.org87f982c2012-02-23 21:34:34 +000027 if (SkXfermode::AsCoeff(paint->getXfermode(), &srcCoeff, &dstCoeff)){
junov@google.com4370aed2012-01-18 16:21:08 +000028 switch (dstCoeff) {
29 case SkXfermode::kZero_Coeff:
30 return true;
31 case SkXfermode::kISA_Coeff:
junov@chromium.org87f982c2012-02-23 21:34:34 +000032 if (paint->getAlpha() != 255) {
junov@google.com4370aed2012-01-18 16:21:08 +000033 break;
34 }
35 if (bmpReplacesShader) {
36 if (!bmpReplacesShader->isOpaque()) {
37 break;
38 }
junov@chromium.org87f982c2012-02-23 21:34:34 +000039 } else if (paint->getShader() && !paint->getShader()->isOpaque()) {
junov@google.com4370aed2012-01-18 16:21:08 +000040 break;
41 }
junov@chromium.org87f982c2012-02-23 21:34:34 +000042 if (paint->getColorFilter() && ((paint->getColorFilter()->getFlags() &
junov@google.com4370aed2012-01-18 16:21:08 +000043 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
44 break;
45 }
46 return true;
47 case SkXfermode::kSA_Coeff:
junov@chromium.org87f982c2012-02-23 21:34:34 +000048 if (paint->getAlpha() != 0) {
junov@google.com4370aed2012-01-18 16:21:08 +000049 break;
50 }
junov@chromium.org87f982c2012-02-23 21:34:34 +000051 if (paint->getColorFilter() && ((paint->getColorFilter()->getFlags() &
junov@google.com4370aed2012-01-18 16:21:08 +000052 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
53 break;
54 }
55 return true;
56 case SkXfermode::kSC_Coeff:
junov@chromium.org87f982c2012-02-23 21:34:34 +000057 if (paint->getColor() != 0) { // all components must be 0
junov@google.com4370aed2012-01-18 16:21:08 +000058 break;
59 }
junov@chromium.org87f982c2012-02-23 21:34:34 +000060 if (bmpReplacesShader || paint->getShader()) {
junov@google.com4370aed2012-01-18 16:21:08 +000061 break;
62 }
junov@chromium.org87f982c2012-02-23 21:34:34 +000063 if (paint->getColorFilter() && ((paint->getColorFilter()->getFlags() &
junov@google.com4370aed2012-01-18 16:21:08 +000064 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
65 break;
66 }
67 return true;
68 default:
69 break;
70 }
71 }
72 return false;
73}
74
75} // unnamed namespace
76
77SkDeferredCanvas::SkDeferredCanvas()
78{
79 init();
80}
81
82SkDeferredCanvas::SkDeferredCanvas(SkDevice* device)
83{
84 init();
85 setDevice(device);
86}
87
88SkDeferredCanvas::SkDeferredCanvas(SkDevice* device,
89 DeviceContext* deviceContext)
90{
91 init();
92 setDevice(device);
93 setDeviceContext(deviceContext);
94}
95
96void SkDeferredCanvas::init()
97{
98 fDeferredDrawing = true; // On by default
99}
100
101void SkDeferredCanvas::validate() const
102{
103 SkASSERT(getDevice());
junov@google.com4370aed2012-01-18 16:21:08 +0000104}
105
106SkCanvas* SkDeferredCanvas::drawingCanvas() const
107{
108 validate();
109 return fDeferredDrawing ? getDeferredDevice()->recordingCanvas() :
110 getDeferredDevice()->immediateCanvas();
111}
112
113void SkDeferredCanvas::flushIfNeeded(const SkBitmap& bitmap)
114{
115 validate();
116 if (fDeferredDrawing) {
117 getDeferredDevice()->flushIfNeeded(bitmap);
118 }
119}
120
121SkDeferredCanvas::DeferredDevice* SkDeferredCanvas::getDeferredDevice() const
122{
123 return static_cast<SkDeferredCanvas::DeferredDevice*>(getDevice());
124}
125
126void SkDeferredCanvas::setDeferredDrawing(bool val)
127{
128 validate(); // Must set device before calling this method
129 SkASSERT(drawingCanvas()->getSaveCount() == 1);
130 if (val != fDeferredDrawing) {
131 if (fDeferredDrawing) {
132 // Going live.
133 getDeferredDevice()->flushPending();
134 }
135 fDeferredDrawing = val;
136 }
137}
138
139SkDeferredCanvas::~SkDeferredCanvas()
140{
141}
142
143SkDevice* SkDeferredCanvas::setDevice(SkDevice* device)
144{
145 INHERITED::setDevice(SkNEW_ARGS(DeferredDevice, (device)))->unref();
146 return device;
147}
148
149SkDeferredCanvas::DeviceContext* SkDeferredCanvas::setDeviceContext(
150 DeviceContext* deviceContext)
151{
152 DeferredDevice* deferredDevice = getDeferredDevice();
153 SkASSERT(deferredDevice);
154 if (deferredDevice) {
155 deferredDevice->setDeviceContext(deviceContext);
156 }
157 return deviceContext;
158}
159
160bool SkDeferredCanvas::isFullFrame(const SkRect* rect,
161 const SkPaint* paint) const
162{
163 SkCanvas* canvas = drawingCanvas();
164 SkISize canvasSize = getDeviceSize();
165 if (rect) {
166 if (!canvas->getTotalMatrix().rectStaysRect()) {
167 return false; // conservative
168 }
169
170 SkRect transformedRect;
171 canvas->getTotalMatrix().mapRect(&transformedRect, *rect);
172
173 if (paint) {
174 SkPaint::Style paintStyle = paint->getStyle();
175 if (!(paintStyle == SkPaint::kFill_Style ||
176 paintStyle == SkPaint::kStrokeAndFill_Style)) {
177 return false;
178 }
179 if (paint->getMaskFilter() || paint->getLooper()
180 || paint->getPathEffect() || paint->getImageFilter()) {
181 return false; // conservative
182 }
183 }
184
185 // The following test holds with AA enabled, and is conservative
186 // by a 0.5 pixel margin with AA disabled
junov@chromium.orgb1e218e2012-02-13 22:27:58 +0000187 if (transformedRect.fLeft > SkIntToScalar(0) ||
188 transformedRect.fTop > SkIntToScalar(0) ||
189 transformedRect.fRight < SkIntToScalar(canvasSize.fWidth) ||
190 transformedRect.fBottom < SkIntToScalar(canvasSize.fHeight)) {
junov@google.com4370aed2012-01-18 16:21:08 +0000191 return false;
192 }
193 }
194
195 switch (canvas->getClipType()) {
196 case SkCanvas::kRect_ClipType :
197 {
198 SkIRect bounds;
199 canvas->getClipDeviceBounds(&bounds);
200 if (bounds.fLeft > 0 || bounds.fTop > 0 ||
201 bounds.fRight < canvasSize.fWidth ||
202 bounds.fBottom < canvasSize.fHeight)
203 return false;
204 }
205 break;
206 case SkCanvas::kComplex_ClipType :
207 return false; // conservative
208 case SkCanvas::kEmpty_ClipType:
209 default:
210 break;
211 };
212
213 return true;
214}
215
216int SkDeferredCanvas::save(SaveFlags flags)
217{
junov@chromium.orga907ac32012-02-24 21:54:07 +0000218 drawingCanvas()->save(flags);
219 return this->INHERITED::save(flags);
junov@google.com4370aed2012-01-18 16:21:08 +0000220}
221
222int SkDeferredCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
223 SaveFlags flags)
224{
junov@chromium.orga907ac32012-02-24 21:54:07 +0000225 drawingCanvas()->saveLayer(bounds, paint, flags);
226 int count = this->INHERITED::save(flags);
227 this->clipRectBounds(bounds, flags, NULL);
228 return count;
junov@google.com4370aed2012-01-18 16:21:08 +0000229}
230
231void SkDeferredCanvas::restore()
232{
233 drawingCanvas()->restore();
junov@chromium.orga907ac32012-02-24 21:54:07 +0000234 this->INHERITED::restore();
junov@google.com4370aed2012-01-18 16:21:08 +0000235}
236
junov@chromium.orga907ac32012-02-24 21:54:07 +0000237bool SkDeferredCanvas::isDrawingToLayer() const
junov@google.com4370aed2012-01-18 16:21:08 +0000238{
junov@chromium.orga907ac32012-02-24 21:54:07 +0000239 return drawingCanvas()->isDrawingToLayer();
junov@google.com4370aed2012-01-18 16:21:08 +0000240}
241
242bool SkDeferredCanvas::translate(SkScalar dx, SkScalar dy)
243{
junov@chromium.orga907ac32012-02-24 21:54:07 +0000244 drawingCanvas()->translate(dx, dy);
245 return this->INHERITED::translate(dx, dy);
junov@google.com4370aed2012-01-18 16:21:08 +0000246}
247
248bool SkDeferredCanvas::scale(SkScalar sx, SkScalar sy)
249{
junov@chromium.orga907ac32012-02-24 21:54:07 +0000250 drawingCanvas()->scale(sx, sy);
251 return this->INHERITED::scale(sx, sy);
junov@google.com4370aed2012-01-18 16:21:08 +0000252}
253
254bool SkDeferredCanvas::rotate(SkScalar degrees)
255{
junov@chromium.orga907ac32012-02-24 21:54:07 +0000256 drawingCanvas()->rotate(degrees);
257 return this->INHERITED::rotate(degrees);
junov@google.com4370aed2012-01-18 16:21:08 +0000258}
259
260bool SkDeferredCanvas::skew(SkScalar sx, SkScalar sy)
261{
junov@chromium.orga907ac32012-02-24 21:54:07 +0000262 drawingCanvas()->skew(sx, sy);
263 return this->INHERITED::skew(sx, sy);
junov@google.com4370aed2012-01-18 16:21:08 +0000264}
265
266bool SkDeferredCanvas::concat(const SkMatrix& matrix)
267{
junov@chromium.orga907ac32012-02-24 21:54:07 +0000268 drawingCanvas()->concat(matrix);
269 return this->INHERITED::concat(matrix);
junov@google.com4370aed2012-01-18 16:21:08 +0000270}
271
272void SkDeferredCanvas::setMatrix(const SkMatrix& matrix)
273{
274 drawingCanvas()->setMatrix(matrix);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000275 this->INHERITED::setMatrix(matrix);
junov@google.com4370aed2012-01-18 16:21:08 +0000276}
277
278bool SkDeferredCanvas::clipRect(const SkRect& rect,
279 SkRegion::Op op,
280 bool doAntiAlias)
281{
junov@chromium.orga907ac32012-02-24 21:54:07 +0000282 drawingCanvas()->clipRect(rect, op, doAntiAlias);
283 return this->INHERITED::clipRect(rect, op, doAntiAlias);
junov@google.com4370aed2012-01-18 16:21:08 +0000284}
285
286bool SkDeferredCanvas::clipPath(const SkPath& path,
287 SkRegion::Op op,
288 bool doAntiAlias)
289{
junov@chromium.orga907ac32012-02-24 21:54:07 +0000290 drawingCanvas()->clipPath(path, op, doAntiAlias);
291 return this->INHERITED::clipPath(path, op, doAntiAlias);
junov@google.com4370aed2012-01-18 16:21:08 +0000292}
293
294bool SkDeferredCanvas::clipRegion(const SkRegion& deviceRgn,
295 SkRegion::Op op)
296{
junov@chromium.orga907ac32012-02-24 21:54:07 +0000297 drawingCanvas()->clipRegion(deviceRgn, op);
298 return this->INHERITED::clipRegion(deviceRgn, op);
junov@google.com4370aed2012-01-18 16:21:08 +0000299}
300
301void SkDeferredCanvas::clear(SkColor color)
302{
303 // purge pending commands
304 if (fDeferredDrawing) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000305 getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000306 }
307
308 drawingCanvas()->clear(color);
309}
310
311void SkDeferredCanvas::drawPaint(const SkPaint& paint)
312{
junov@chromium.org87f982c2012-02-23 21:34:34 +0000313 if (fDeferredDrawing && isFullFrame(NULL, &paint) && isPaintOpaque(&paint)) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000314 getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000315 }
316
317 drawingCanvas()->drawPaint(paint);
318}
319
320void SkDeferredCanvas::drawPoints(PointMode mode, size_t count,
321 const SkPoint pts[], const SkPaint& paint)
322{
323 drawingCanvas()->drawPoints(mode, count, pts, paint);
324}
325
326void SkDeferredCanvas::drawRect(const SkRect& rect, const SkPaint& paint)
327{
junov@chromium.org87f982c2012-02-23 21:34:34 +0000328 if (fDeferredDrawing && isFullFrame(&rect, &paint) && isPaintOpaque(&paint)) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000329 getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000330 }
331
332 drawingCanvas()->drawRect(rect, paint);
333}
334
335void SkDeferredCanvas::drawPath(const SkPath& path, const SkPaint& paint)
336{
337 drawingCanvas()->drawPath(path, paint);
338}
339
340void SkDeferredCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left,
341 SkScalar top, const SkPaint* paint)
342{
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000343 SkRect bitmapRect = SkRect::MakeXYWH(left, top,
344 SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height()));
junov@google.com4370aed2012-01-18 16:21:08 +0000345 if (fDeferredDrawing &&
346 isFullFrame(&bitmapRect, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000347 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000348 getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000349 }
350
351 drawingCanvas()->drawBitmap(bitmap, left, top, paint);
352 flushIfNeeded(bitmap);
353}
354
355void SkDeferredCanvas::drawBitmapRect(const SkBitmap& bitmap,
356 const SkIRect* src,
357 const SkRect& dst, const SkPaint* paint)
358{
359 if (fDeferredDrawing &&
360 isFullFrame(&dst, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000361 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000362 getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000363 }
364
365 drawingCanvas()->drawBitmapRect(bitmap, src,
366 dst, paint);
367 flushIfNeeded(bitmap);
368}
369
370
371void SkDeferredCanvas::drawBitmapMatrix(const SkBitmap& bitmap,
372 const SkMatrix& m,
373 const SkPaint* paint)
374{
375 // TODO: reset recording canvas if paint+bitmap is opaque and clip rect
376 // covers canvas entirely and transformed bitmap covers canvas entirely
377 drawingCanvas()->drawBitmapMatrix(bitmap, m, paint);
378 flushIfNeeded(bitmap);
379}
380
381void SkDeferredCanvas::drawBitmapNine(const SkBitmap& bitmap,
382 const SkIRect& center, const SkRect& dst,
383 const SkPaint* paint)
384{
385 // TODO: reset recording canvas if paint+bitmap is opaque and clip rect
386 // covers canvas entirely and dst covers canvas entirely
387 drawingCanvas()->drawBitmapNine(bitmap, center,
388 dst, paint);
389 flushIfNeeded(bitmap);
390}
391
392void SkDeferredCanvas::drawSprite(const SkBitmap& bitmap, int left, int top,
393 const SkPaint* paint)
394{
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000395 SkRect bitmapRect = SkRect::MakeXYWH(
396 SkIntToScalar(left),
397 SkIntToScalar(top),
398 SkIntToScalar(bitmap.width()),
399 SkIntToScalar(bitmap.height()));
junov@google.com4370aed2012-01-18 16:21:08 +0000400 if (fDeferredDrawing &&
401 isFullFrame(&bitmapRect, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000402 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000403 getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000404 }
405
406 drawingCanvas()->drawSprite(bitmap, left, top,
407 paint);
408 flushIfNeeded(bitmap);
409}
410
411void SkDeferredCanvas::drawText(const void* text, size_t byteLength,
412 SkScalar x, SkScalar y, const SkPaint& paint)
413{
414 drawingCanvas()->drawText(text, byteLength, x,
415 y, paint);
416}
417
418void SkDeferredCanvas::drawPosText(const void* text, size_t byteLength,
419 const SkPoint pos[], const SkPaint& paint)
420{
421 drawingCanvas()->drawPosText(text, byteLength,
422 pos, paint);
423}
424
425void SkDeferredCanvas::drawPosTextH(const void* text, size_t byteLength,
426 const SkScalar xpos[], SkScalar constY,
427 const SkPaint& paint)
428{
429 drawingCanvas()->drawPosTextH(text, byteLength,
430 xpos, constY,
431 paint);
432}
433
434void SkDeferredCanvas::drawTextOnPath(const void* text, size_t byteLength,
435 const SkPath& path,
436 const SkMatrix* matrix,
437 const SkPaint& paint)
438{
439 drawingCanvas()->drawTextOnPath(text, byteLength,
440 path, matrix,
441 paint);
442}
443
444void SkDeferredCanvas::drawPicture(SkPicture& picture)
445{
446 drawingCanvas()->drawPicture(picture);
447}
448
449void SkDeferredCanvas::drawVertices(VertexMode vmode, int vertexCount,
450 const SkPoint vertices[],
451 const SkPoint texs[],
452 const SkColor colors[], SkXfermode* xmode,
453 const uint16_t indices[], int indexCount,
454 const SkPaint& paint)
455{
456 drawingCanvas()->drawVertices(vmode, vertexCount,
457 vertices, texs,
458 colors, xmode,
459 indices, indexCount,
460 paint);
461}
462
463SkBounder* SkDeferredCanvas::setBounder(SkBounder* bounder)
464{
junov@chromium.orga907ac32012-02-24 21:54:07 +0000465 drawingCanvas()->setBounder(bounder);
466 return INHERITED::setBounder(bounder);
junov@google.com4370aed2012-01-18 16:21:08 +0000467}
468
469SkDrawFilter* SkDeferredCanvas::setDrawFilter(SkDrawFilter* filter)
470{
junov@chromium.orga907ac32012-02-24 21:54:07 +0000471 drawingCanvas()->setDrawFilter(filter);
472 return INHERITED::setDrawFilter(filter); // So non-virtual getDrawFilter works
junov@google.com4370aed2012-01-18 16:21:08 +0000473}
474
475SkCanvas* SkDeferredCanvas::canvasForDrawIter() {
476 return drawingCanvas();
477}
478
479// SkDeferredCanvas::DeferredDevice
480//------------------------------------
481
482SkDeferredCanvas::DeferredDevice::DeferredDevice(
483 SkDevice* immediateDevice, DeviceContext* deviceContext) :
484 SkDevice(SkBitmap::kNo_Config, immediateDevice->width(),
485 immediateDevice->height(), immediateDevice->isOpaque())
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000486 , fFreshFrame(true)
junov@google.com4370aed2012-01-18 16:21:08 +0000487{
488 fDeviceContext = deviceContext;
489 SkSafeRef(fDeviceContext);
490 fImmediateDevice = immediateDevice; // ref counted via fImmediateCanvas
491 fImmediateCanvas = SkNEW_ARGS(SkCanvas, (fImmediateDevice));
junov@google.com4370aed2012-01-18 16:21:08 +0000492 fRecordingCanvas = fPicture.beginRecording(fImmediateDevice->width(),
junov@chromium.orga907ac32012-02-24 21:54:07 +0000493 fImmediateDevice->height(), 0);
junov@google.com4370aed2012-01-18 16:21:08 +0000494}
495
496SkDeferredCanvas::DeferredDevice::~DeferredDevice()
497{
498 SkSafeUnref(fImmediateCanvas);
499 SkSafeUnref(fDeviceContext);
500}
501
502void SkDeferredCanvas::DeferredDevice::setDeviceContext(
503 DeviceContext* deviceContext)
504{
505 SkRefCnt_SafeAssign(fDeviceContext, deviceContext);
506}
507
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000508void SkDeferredCanvas::DeferredDevice::contentsCleared()
junov@google.com4370aed2012-01-18 16:21:08 +0000509{
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000510 if (!fRecordingCanvas->isDrawingToLayer()) {
511 fFreshFrame = true;
junov@google.com4370aed2012-01-18 16:21:08 +0000512
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000513 // TODO: find a way to transfer the state stack and layers
514 // to the new recording canvas. For now, purging only works
515 // with an empty stack.
516 if (fRecordingCanvas->getSaveCount() == 0) {
junov@google.com4370aed2012-01-18 16:21:08 +0000517
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000518 // Save state that is trashed by the purge
519 SkDrawFilter* drawFilter = fRecordingCanvas->getDrawFilter();
520 SkSafeRef(drawFilter); // So that it survives the purge
521 SkMatrix matrix = fRecordingCanvas->getTotalMatrix();
522 SkRegion clipRegion = fRecordingCanvas->getTotalClip();
junov@google.com4370aed2012-01-18 16:21:08 +0000523
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000524 // beginRecording creates a new recording canvas and discards the
525 // old one, hence purging deferred draw ops.
526 fRecordingCanvas = fPicture.beginRecording(
527 fImmediateDevice->width(),
junov@chromium.orga907ac32012-02-24 21:54:07 +0000528 fImmediateDevice->height(), 0);
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000529
530 // Restore pre-purge state
531 if (!clipRegion.isEmpty()) {
532 fRecordingCanvas->clipRegion(clipRegion, SkRegion::kReplace_Op);
533 }
534 if (!matrix.isIdentity()) {
535 fRecordingCanvas->setMatrix(matrix);
536 }
537 if (drawFilter) {
538 fRecordingCanvas->setDrawFilter(drawFilter)->unref();
539 }
540 }
junov@google.com4370aed2012-01-18 16:21:08 +0000541 }
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000542}
543
544bool SkDeferredCanvas::DeferredDevice::isFreshFrame() {
545 bool ret = fFreshFrame;
546 fFreshFrame = false;
547 return ret;
junov@google.com4370aed2012-01-18 16:21:08 +0000548}
549
550void SkDeferredCanvas::DeferredDevice::flushPending()
551{
552 if (fDeviceContext) {
553 fDeviceContext->prepareForDraw();
554 }
555 fPicture.draw(fImmediateCanvas);
556 fRecordingCanvas = fPicture.beginRecording(fImmediateDevice->width(),
junov@chromium.orga907ac32012-02-24 21:54:07 +0000557 fImmediateDevice->height(), 0);
junov@google.com4370aed2012-01-18 16:21:08 +0000558}
559
560void SkDeferredCanvas::DeferredDevice::flush()
561{
562 flushPending();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000563 fImmediateCanvas->flush();
junov@google.com4370aed2012-01-18 16:21:08 +0000564}
565
junov@google.com4370aed2012-01-18 16:21:08 +0000566void SkDeferredCanvas::DeferredDevice::flushIfNeeded(const SkBitmap& bitmap)
567{
568 if (bitmap.isImmutable()) {
569 return; // safe to deffer without registering a dependency
570 }
571
572 // For now, drawing a writable bitmap triggers a flush
573 // TODO: implement read-only semantics and auto buffer duplication on write
574 // in SkBitmap/SkPixelRef, which will make deferral possible in this case.
575 flushPending();
576}
577
578uint32_t SkDeferredCanvas::DeferredDevice::getDeviceCapabilities()
579{
580 return fImmediateDevice->getDeviceCapabilities();
581}
582
583int SkDeferredCanvas::DeferredDevice::width() const
584{
585 return fImmediateDevice->width();
586}
587
588int SkDeferredCanvas::DeferredDevice::height() const
589{
590 return fImmediateDevice->height();
591}
592
593SkGpuRenderTarget* SkDeferredCanvas::DeferredDevice::accessRenderTarget()
594{
595 flushPending();
596 return fImmediateDevice->accessRenderTarget();
597}
598
599void SkDeferredCanvas::DeferredDevice::writePixels(const SkBitmap& bitmap,
600 int x, int y, SkCanvas::Config8888 config8888)
601{
602 if (x <= 0 && y <= 0 && (x + bitmap.width()) >= width() &&
603 (y + bitmap.height()) >= height()) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000604 contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000605 }
606
607 if (SkBitmap::kARGB_8888_Config == bitmap.config() &&
608 SkCanvas::kNative_Premul_Config8888 != config8888 &&
609 kPMColorAlias != config8888) {
610 //Special case config: no deferral
611 flushPending();
612 fImmediateDevice->writePixels(bitmap, x, y, config8888);
613 }
614
615 SkPaint paint;
616 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
617 fRecordingCanvas->drawSprite(bitmap, x, y, &paint);
618 flushIfNeeded(bitmap);
619}
620
junov@chromium.org1f9767c2012-02-07 16:27:57 +0000621const SkBitmap& SkDeferredCanvas::DeferredDevice::onAccessBitmap(SkBitmap*)
junov@google.com4370aed2012-01-18 16:21:08 +0000622{
junov@google.com4370aed2012-01-18 16:21:08 +0000623 flushPending();
junov@chromium.org1f9767c2012-02-07 16:27:57 +0000624 return fImmediateDevice->accessBitmap(false);
junov@google.com4370aed2012-01-18 16:21:08 +0000625}
626
627SkDevice* SkDeferredCanvas::DeferredDevice::onCreateCompatibleDevice(
628 SkBitmap::Config config, int width, int height, bool isOpaque, Usage usage)
629{
630 // Save layer usage not supported, and not required by SkDeferredCanvas.
631 SkASSERT(usage != kSaveLayer_Usage);
632 // Create a compatible non-deferred device.
633 SkDevice* compatibleDevice = fImmediateDevice->createCompatibleDevice(config, width,
634 height, isOpaque);
635 return SkNEW_ARGS(DeferredDevice, (compatibleDevice, fDeviceContext));
636}
637
638bool SkDeferredCanvas::DeferredDevice::onReadPixels(
639 const SkBitmap& bitmap, int x, int y, SkCanvas::Config8888 config8888)
640{
641 flushPending();
642 return fImmediateCanvas->readPixels(const_cast<SkBitmap*>(&bitmap),
643 x, y, config8888);
644}