blob: 6988517fe67b82230bdaf56b31ff5c3b73a12838 [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
18bool isPaintOpaque(const SkPaint& paint, const SkBitmap* bmpReplacesShader = NULL) {
19 // TODO: SkXfermode should have a virtual isOpaque method, which would
20 // make it possible to test modes that do not have a Coeff representation.
21 SkXfermode::Coeff srcCoeff, dstCoeff;
22 if (SkXfermode::AsCoeff(paint.getXfermode(), &srcCoeff, &dstCoeff)){
23 switch (dstCoeff) {
24 case SkXfermode::kZero_Coeff:
25 return true;
26 case SkXfermode::kISA_Coeff:
27 if (paint.getAlpha() != 255) {
28 break;
29 }
30 if (bmpReplacesShader) {
31 if (!bmpReplacesShader->isOpaque()) {
32 break;
33 }
34 } else if (paint.getShader() && !paint.getShader()->isOpaque()) {
35 break;
36 }
37 if (paint.getColorFilter() && ((paint.getColorFilter()->getFlags() &
38 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
39 break;
40 }
41 return true;
42 case SkXfermode::kSA_Coeff:
43 if (paint.getAlpha() != 0) {
44 break;
45 }
46 if (paint.getColorFilter() && ((paint.getColorFilter()->getFlags() &
47 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
48 break;
49 }
50 return true;
51 case SkXfermode::kSC_Coeff:
52 if (paint.getColor() != 0) { // all components must be 0
53 break;
54 }
55 if (bmpReplacesShader || paint.getShader()) {
56 break;
57 }
58 if (paint.getColorFilter() && ((paint.getColorFilter()->getFlags() &
59 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
60 break;
61 }
62 return true;
63 default:
64 break;
65 }
66 }
67 return false;
68}
69
70} // unnamed namespace
71
72SkDeferredCanvas::SkDeferredCanvas()
73{
74 init();
75}
76
77SkDeferredCanvas::SkDeferredCanvas(SkDevice* device)
78{
79 init();
80 setDevice(device);
81}
82
83SkDeferredCanvas::SkDeferredCanvas(SkDevice* device,
84 DeviceContext* deviceContext)
85{
86 init();
87 setDevice(device);
88 setDeviceContext(deviceContext);
89}
90
91void SkDeferredCanvas::init()
92{
93 fDeferredDrawing = true; // On by default
94}
95
96void SkDeferredCanvas::validate() const
97{
98 SkASSERT(getDevice());
99 SkASSERT(INHERITED::getTotalMatrix().isIdentity());
100}
101
102SkCanvas* SkDeferredCanvas::drawingCanvas() const
103{
104 validate();
105 return fDeferredDrawing ? getDeferredDevice()->recordingCanvas() :
106 getDeferredDevice()->immediateCanvas();
107}
108
109void SkDeferredCanvas::flushIfNeeded(const SkBitmap& bitmap)
110{
111 validate();
112 if (fDeferredDrawing) {
113 getDeferredDevice()->flushIfNeeded(bitmap);
114 }
115}
116
117SkDeferredCanvas::DeferredDevice* SkDeferredCanvas::getDeferredDevice() const
118{
119 return static_cast<SkDeferredCanvas::DeferredDevice*>(getDevice());
120}
121
122void SkDeferredCanvas::setDeferredDrawing(bool val)
123{
124 validate(); // Must set device before calling this method
125 SkASSERT(drawingCanvas()->getSaveCount() == 1);
126 if (val != fDeferredDrawing) {
127 if (fDeferredDrawing) {
128 // Going live.
129 getDeferredDevice()->flushPending();
130 }
131 fDeferredDrawing = val;
132 }
133}
134
135SkDeferredCanvas::~SkDeferredCanvas()
136{
137}
138
139SkDevice* SkDeferredCanvas::setDevice(SkDevice* device)
140{
141 INHERITED::setDevice(SkNEW_ARGS(DeferredDevice, (device)))->unref();
142 return device;
143}
144
145SkDeferredCanvas::DeviceContext* SkDeferredCanvas::setDeviceContext(
146 DeviceContext* deviceContext)
147{
148 DeferredDevice* deferredDevice = getDeferredDevice();
149 SkASSERT(deferredDevice);
150 if (deferredDevice) {
151 deferredDevice->setDeviceContext(deviceContext);
152 }
153 return deviceContext;
154}
155
156bool SkDeferredCanvas::isFullFrame(const SkRect* rect,
157 const SkPaint* paint) const
158{
159 SkCanvas* canvas = drawingCanvas();
160 SkISize canvasSize = getDeviceSize();
161 if (rect) {
162 if (!canvas->getTotalMatrix().rectStaysRect()) {
163 return false; // conservative
164 }
165
166 SkRect transformedRect;
167 canvas->getTotalMatrix().mapRect(&transformedRect, *rect);
168
169 if (paint) {
170 SkPaint::Style paintStyle = paint->getStyle();
171 if (!(paintStyle == SkPaint::kFill_Style ||
172 paintStyle == SkPaint::kStrokeAndFill_Style)) {
173 return false;
174 }
175 if (paint->getMaskFilter() || paint->getLooper()
176 || paint->getPathEffect() || paint->getImageFilter()) {
177 return false; // conservative
178 }
179 }
180
181 // The following test holds with AA enabled, and is conservative
182 // by a 0.5 pixel margin with AA disabled
183 if (transformedRect.fLeft > 0 || transformedRect.fTop > 0 ||
184 transformedRect.fRight < canvasSize.fWidth ||
185 transformedRect.fBottom < canvasSize.fHeight) {
186 return false;
187 }
188 }
189
190 switch (canvas->getClipType()) {
191 case SkCanvas::kRect_ClipType :
192 {
193 SkIRect bounds;
194 canvas->getClipDeviceBounds(&bounds);
195 if (bounds.fLeft > 0 || bounds.fTop > 0 ||
196 bounds.fRight < canvasSize.fWidth ||
197 bounds.fBottom < canvasSize.fHeight)
198 return false;
199 }
200 break;
201 case SkCanvas::kComplex_ClipType :
202 return false; // conservative
203 case SkCanvas::kEmpty_ClipType:
204 default:
205 break;
206 };
207
208 return true;
209}
210
211int SkDeferredCanvas::save(SaveFlags flags)
212{
213 return drawingCanvas()->save(flags);
214}
215
216int SkDeferredCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
217 SaveFlags flags)
218{
219 return drawingCanvas()->saveLayer(bounds, paint, flags);
220}
221
222void SkDeferredCanvas::restore()
223{
224 drawingCanvas()->restore();
225}
226
227int SkDeferredCanvas::getSaveCount() const
228{
229 return drawingCanvas()->getSaveCount();
230}
231
232bool SkDeferredCanvas::translate(SkScalar dx, SkScalar dy)
233{
234 return drawingCanvas()->translate(dx, dy);
235}
236
237bool SkDeferredCanvas::scale(SkScalar sx, SkScalar sy)
238{
239 return drawingCanvas()->scale(sx, sy);
240}
241
242bool SkDeferredCanvas::rotate(SkScalar degrees)
243{
244 return drawingCanvas()->rotate(degrees);
245}
246
247bool SkDeferredCanvas::skew(SkScalar sx, SkScalar sy)
248{
249 return drawingCanvas()->skew(sx, sy);
250}
251
252bool SkDeferredCanvas::concat(const SkMatrix& matrix)
253{
254 return drawingCanvas()->concat(matrix);
255}
256
257void SkDeferredCanvas::setMatrix(const SkMatrix& matrix)
258{
259 drawingCanvas()->setMatrix(matrix);
260}
261
262const SkMatrix& SkDeferredCanvas::getTotalMatrix() const
263{
264 return drawingCanvas()->getTotalMatrix();
265}
266
267bool SkDeferredCanvas::clipRect(const SkRect& rect,
268 SkRegion::Op op,
269 bool doAntiAlias)
270{
271 return drawingCanvas()->clipRect(rect, op, doAntiAlias);
272}
273
274bool SkDeferredCanvas::clipPath(const SkPath& path,
275 SkRegion::Op op,
276 bool doAntiAlias)
277{
278 return drawingCanvas()->clipPath(path, op, doAntiAlias);
279}
280
281bool SkDeferredCanvas::clipRegion(const SkRegion& deviceRgn,
282 SkRegion::Op op)
283{
284 return drawingCanvas()->clipRegion(deviceRgn, op);
285}
286
287void SkDeferredCanvas::clear(SkColor color)
288{
289 // purge pending commands
290 if (fDeferredDrawing) {
291 getDeferredDevice()->purgePending();
292 }
293
294 drawingCanvas()->clear(color);
295}
296
297void SkDeferredCanvas::drawPaint(const SkPaint& paint)
298{
299 if (fDeferredDrawing && isFullFrame(NULL, &paint) && isPaintOpaque(paint)) {
300 getDeferredDevice()->purgePending();
301 }
302
303 drawingCanvas()->drawPaint(paint);
304}
305
306void SkDeferredCanvas::drawPoints(PointMode mode, size_t count,
307 const SkPoint pts[], const SkPaint& paint)
308{
309 drawingCanvas()->drawPoints(mode, count, pts, paint);
310}
311
312void SkDeferredCanvas::drawRect(const SkRect& rect, const SkPaint& paint)
313{
314 if (fDeferredDrawing && isFullFrame(&rect, &paint) && isPaintOpaque(paint)) {
315 getDeferredDevice()->purgePending();
316 }
317
318 drawingCanvas()->drawRect(rect, paint);
319}
320
321void SkDeferredCanvas::drawPath(const SkPath& path, const SkPaint& paint)
322{
323 drawingCanvas()->drawPath(path, paint);
324}
325
326void SkDeferredCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left,
327 SkScalar top, const SkPaint* paint)
328{
329 SkRect bitmapRect = SkRect::MakeXYWH(left, top, bitmap.width(),
330 bitmap.height());
331 if (fDeferredDrawing &&
332 isFullFrame(&bitmapRect, paint) &&
333 isPaintOpaque(*paint, &bitmap)) {
334 getDeferredDevice()->purgePending();
335 }
336
337 drawingCanvas()->drawBitmap(bitmap, left, top, paint);
338 flushIfNeeded(bitmap);
339}
340
341void SkDeferredCanvas::drawBitmapRect(const SkBitmap& bitmap,
342 const SkIRect* src,
343 const SkRect& dst, const SkPaint* paint)
344{
345 if (fDeferredDrawing &&
346 isFullFrame(&dst, paint) &&
347 isPaintOpaque(*paint, &bitmap)) {
348 getDeferredDevice()->purgePending();
349 }
350
351 drawingCanvas()->drawBitmapRect(bitmap, src,
352 dst, paint);
353 flushIfNeeded(bitmap);
354}
355
356
357void SkDeferredCanvas::drawBitmapMatrix(const SkBitmap& bitmap,
358 const SkMatrix& m,
359 const SkPaint* paint)
360{
361 // TODO: reset recording canvas if paint+bitmap is opaque and clip rect
362 // covers canvas entirely and transformed bitmap covers canvas entirely
363 drawingCanvas()->drawBitmapMatrix(bitmap, m, paint);
364 flushIfNeeded(bitmap);
365}
366
367void SkDeferredCanvas::drawBitmapNine(const SkBitmap& bitmap,
368 const SkIRect& center, const SkRect& dst,
369 const SkPaint* paint)
370{
371 // TODO: reset recording canvas if paint+bitmap is opaque and clip rect
372 // covers canvas entirely and dst covers canvas entirely
373 drawingCanvas()->drawBitmapNine(bitmap, center,
374 dst, paint);
375 flushIfNeeded(bitmap);
376}
377
378void SkDeferredCanvas::drawSprite(const SkBitmap& bitmap, int left, int top,
379 const SkPaint* paint)
380{
381 SkRect bitmapRect = SkRect::MakeXYWH(left, top, bitmap.width(),
382 bitmap.height());
383 if (fDeferredDrawing &&
384 isFullFrame(&bitmapRect, paint) &&
385 isPaintOpaque(*paint, &bitmap)) {
386 getDeferredDevice()->purgePending();
387 }
388
389 drawingCanvas()->drawSprite(bitmap, left, top,
390 paint);
391 flushIfNeeded(bitmap);
392}
393
394void SkDeferredCanvas::drawText(const void* text, size_t byteLength,
395 SkScalar x, SkScalar y, const SkPaint& paint)
396{
397 drawingCanvas()->drawText(text, byteLength, x,
398 y, paint);
399}
400
401void SkDeferredCanvas::drawPosText(const void* text, size_t byteLength,
402 const SkPoint pos[], const SkPaint& paint)
403{
404 drawingCanvas()->drawPosText(text, byteLength,
405 pos, paint);
406}
407
408void SkDeferredCanvas::drawPosTextH(const void* text, size_t byteLength,
409 const SkScalar xpos[], SkScalar constY,
410 const SkPaint& paint)
411{
412 drawingCanvas()->drawPosTextH(text, byteLength,
413 xpos, constY,
414 paint);
415}
416
417void SkDeferredCanvas::drawTextOnPath(const void* text, size_t byteLength,
418 const SkPath& path,
419 const SkMatrix* matrix,
420 const SkPaint& paint)
421{
422 drawingCanvas()->drawTextOnPath(text, byteLength,
423 path, matrix,
424 paint);
425}
426
427void SkDeferredCanvas::drawPicture(SkPicture& picture)
428{
429 drawingCanvas()->drawPicture(picture);
430}
431
432void SkDeferredCanvas::drawVertices(VertexMode vmode, int vertexCount,
433 const SkPoint vertices[],
434 const SkPoint texs[],
435 const SkColor colors[], SkXfermode* xmode,
436 const uint16_t indices[], int indexCount,
437 const SkPaint& paint)
438{
439 drawingCanvas()->drawVertices(vmode, vertexCount,
440 vertices, texs,
441 colors, xmode,
442 indices, indexCount,
443 paint);
444}
445
446SkBounder* SkDeferredCanvas::setBounder(SkBounder* bounder)
447{
448 INHERITED::setBounder(bounder); // So non-virtual getBounder works
449 return drawingCanvas()->setBounder(bounder);
450}
451
452SkDrawFilter* SkDeferredCanvas::setDrawFilter(SkDrawFilter* filter)
453{
454 INHERITED::setDrawFilter(filter); // So non-virtual getDrawFilter works
455 return drawingCanvas()->setDrawFilter(filter);
456}
457
458SkCanvas* SkDeferredCanvas::canvasForDrawIter() {
459 return drawingCanvas();
460}
461
462// SkDeferredCanvas::DeferredDevice
463//------------------------------------
464
465SkDeferredCanvas::DeferredDevice::DeferredDevice(
466 SkDevice* immediateDevice, DeviceContext* deviceContext) :
467 SkDevice(SkBitmap::kNo_Config, immediateDevice->width(),
468 immediateDevice->height(), immediateDevice->isOpaque())
469{
470 fDeviceContext = deviceContext;
471 SkSafeRef(fDeviceContext);
472 fImmediateDevice = immediateDevice; // ref counted via fImmediateCanvas
473 fImmediateCanvas = SkNEW_ARGS(SkCanvas, (fImmediateDevice));
junov@google.com4370aed2012-01-18 16:21:08 +0000474 fRecordingCanvas = fPicture.beginRecording(fImmediateDevice->width(),
475 fImmediateDevice->height(),
476 SkPicture::kUsePathBoundsForClip_RecordingFlag);
junov@chromium.org1f9767c2012-02-07 16:27:57 +0000477 fBitmapInitialized = false;
junov@google.com4370aed2012-01-18 16:21:08 +0000478}
479
480SkDeferredCanvas::DeferredDevice::~DeferredDevice()
481{
482 SkSafeUnref(fImmediateCanvas);
483 SkSafeUnref(fDeviceContext);
484}
485
486void SkDeferredCanvas::DeferredDevice::setDeviceContext(
487 DeviceContext* deviceContext)
488{
489 SkRefCnt_SafeAssign(fDeviceContext, deviceContext);
490}
491
492void SkDeferredCanvas::DeferredDevice::purgePending()
493{
494 // TODO: find a way to transfer the state stack and layers
495 // to the new recording canvas. For now, purge only works
496 // with an empty stack.
497 if (fRecordingCanvas->getSaveCount() > 1)
498 return;
499
500 // Save state that is trashed by the purge
501 SkDrawFilter* drawFilter = fRecordingCanvas->getDrawFilter();
502 SkSafeRef(drawFilter); // So that it survives the purge
503 SkMatrix matrix = fRecordingCanvas->getTotalMatrix();
504 SkRegion clipRegion = fRecordingCanvas->getTotalClip();
505
506 // beginRecording creates a new recording canvas and discards the old one,
507 // hence purging deferred draw ops.
508 fRecordingCanvas = fPicture.beginRecording(fImmediateDevice->width(),
509 fImmediateDevice->height(),
510 SkPicture::kUsePathBoundsForClip_RecordingFlag);
511
512 // Restore pre-purge state
513 if (!clipRegion.isEmpty()) {
514 fRecordingCanvas->clipRegion(clipRegion, SkRegion::kReplace_Op);
515 }
516 if (!matrix.isIdentity()) {
517 fRecordingCanvas->setMatrix(matrix);
518 }
519 if (drawFilter) {
520 fRecordingCanvas->setDrawFilter(drawFilter)->unref();
521 }
522}
523
524void SkDeferredCanvas::DeferredDevice::flushPending()
525{
526 if (fDeviceContext) {
527 fDeviceContext->prepareForDraw();
528 }
529 fPicture.draw(fImmediateCanvas);
530 fRecordingCanvas = fPicture.beginRecording(fImmediateDevice->width(),
531 fImmediateDevice->height(),
532 SkPicture::kUsePathBoundsForClip_RecordingFlag);
533}
534
535void SkDeferredCanvas::DeferredDevice::flush()
536{
537 flushPending();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000538 fImmediateCanvas->flush();
junov@google.com4370aed2012-01-18 16:21:08 +0000539}
540
junov@google.com4370aed2012-01-18 16:21:08 +0000541void SkDeferredCanvas::DeferredDevice::flushIfNeeded(const SkBitmap& bitmap)
542{
543 if (bitmap.isImmutable()) {
544 return; // safe to deffer without registering a dependency
545 }
546
547 // For now, drawing a writable bitmap triggers a flush
548 // TODO: implement read-only semantics and auto buffer duplication on write
549 // in SkBitmap/SkPixelRef, which will make deferral possible in this case.
550 flushPending();
551}
552
553uint32_t SkDeferredCanvas::DeferredDevice::getDeviceCapabilities()
554{
555 return fImmediateDevice->getDeviceCapabilities();
556}
557
558int SkDeferredCanvas::DeferredDevice::width() const
559{
560 return fImmediateDevice->width();
561}
562
563int SkDeferredCanvas::DeferredDevice::height() const
564{
565 return fImmediateDevice->height();
566}
567
568SkGpuRenderTarget* SkDeferredCanvas::DeferredDevice::accessRenderTarget()
569{
570 flushPending();
571 return fImmediateDevice->accessRenderTarget();
572}
573
574void SkDeferredCanvas::DeferredDevice::writePixels(const SkBitmap& bitmap,
575 int x, int y, SkCanvas::Config8888 config8888)
576{
577 if (x <= 0 && y <= 0 && (x + bitmap.width()) >= width() &&
578 (y + bitmap.height()) >= height()) {
579 purgePending();
580 }
581
582 if (SkBitmap::kARGB_8888_Config == bitmap.config() &&
583 SkCanvas::kNative_Premul_Config8888 != config8888 &&
584 kPMColorAlias != config8888) {
585 //Special case config: no deferral
586 flushPending();
587 fImmediateDevice->writePixels(bitmap, x, y, config8888);
588 }
589
590 SkPaint paint;
591 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
592 fRecordingCanvas->drawSprite(bitmap, x, y, &paint);
593 flushIfNeeded(bitmap);
594}
595
junov@chromium.org1f9767c2012-02-07 16:27:57 +0000596const SkBitmap& SkDeferredCanvas::DeferredDevice::onAccessBitmap(SkBitmap*)
junov@google.com4370aed2012-01-18 16:21:08 +0000597{
junov@google.com4370aed2012-01-18 16:21:08 +0000598 flushPending();
junov@chromium.org1f9767c2012-02-07 16:27:57 +0000599 return fImmediateDevice->accessBitmap(false);
junov@google.com4370aed2012-01-18 16:21:08 +0000600}
601
602SkDevice* SkDeferredCanvas::DeferredDevice::onCreateCompatibleDevice(
603 SkBitmap::Config config, int width, int height, bool isOpaque, Usage usage)
604{
605 // Save layer usage not supported, and not required by SkDeferredCanvas.
606 SkASSERT(usage != kSaveLayer_Usage);
607 // Create a compatible non-deferred device.
608 SkDevice* compatibleDevice = fImmediateDevice->createCompatibleDevice(config, width,
609 height, isOpaque);
610 return SkNEW_ARGS(DeferredDevice, (compatibleDevice, fDeviceContext));
611}
612
613bool SkDeferredCanvas::DeferredDevice::onReadPixels(
614 const SkBitmap& bitmap, int x, int y, SkCanvas::Config8888 config8888)
615{
616 flushPending();
617 return fImmediateCanvas->readPixels(const_cast<SkBitmap*>(&bitmap),
618 x, y, config8888);
619}