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