Home | History | Annotate | Download | only in utils
      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 
     16 namespace {
     17 
     18 bool 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 
     81 SkDeferredCanvas::SkDeferredCanvas() {
     82     init();
     83 }
     84 
     85 SkDeferredCanvas::SkDeferredCanvas(SkDevice* device) {
     86     init();
     87     setDevice(device);
     88 }
     89 
     90 SkDeferredCanvas::SkDeferredCanvas(SkDevice* device,
     91                                    DeviceContext* deviceContext) {
     92     init();
     93     setDevice(device);
     94     setDeviceContext(deviceContext);
     95 }
     96 
     97 void SkDeferredCanvas::init() {
     98     fDeferredDrawing = true; // On by default
     99 }
    100 
    101 void SkDeferredCanvas::validate() const {
    102     SkASSERT(getDevice());
    103 }
    104 
    105 SkCanvas* SkDeferredCanvas::drawingCanvas() const {
    106     validate();
    107     return fDeferredDrawing ? getDeferredDevice()->recordingCanvas() :
    108         getDeferredDevice()->immediateCanvas();
    109 }
    110 
    111 void SkDeferredCanvas::flushIfNeeded(const SkBitmap& bitmap) {
    112     validate();
    113     if (fDeferredDrawing) {
    114         getDeferredDevice()->flushIfNeeded(bitmap);
    115     }
    116 }
    117 
    118 SkDeferredCanvas::DeferredDevice* SkDeferredCanvas::getDeferredDevice() const {
    119     return static_cast<SkDeferredCanvas::DeferredDevice*>(getDevice());
    120 }
    121 
    122 void 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 
    134 SkDeferredCanvas::~SkDeferredCanvas() {
    135 }
    136 
    137 SkDevice* SkDeferredCanvas::setDevice(SkDevice* device) {
    138     INHERITED::setDevice(SkNEW_ARGS(DeferredDevice, (device)))->unref();
    139     return device;
    140 }
    141 
    142 SkDeferredCanvas::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 
    153 bool 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 
    208 int SkDeferredCanvas::save(SaveFlags flags) {
    209     drawingCanvas()->save(flags);
    210     return this->INHERITED::save(flags);
    211 }
    212 
    213 int 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 
    221 void SkDeferredCanvas::restore() {
    222     drawingCanvas()->restore();
    223     this->INHERITED::restore();
    224 }
    225 
    226 bool SkDeferredCanvas::isDrawingToLayer() const {
    227     return drawingCanvas()->isDrawingToLayer();
    228 }
    229 
    230 bool SkDeferredCanvas::translate(SkScalar dx, SkScalar dy) {
    231     drawingCanvas()->translate(dx, dy);
    232     return this->INHERITED::translate(dx, dy);
    233 }
    234 
    235 bool SkDeferredCanvas::scale(SkScalar sx, SkScalar sy) {
    236     drawingCanvas()->scale(sx, sy);
    237     return this->INHERITED::scale(sx, sy);
    238 }
    239 
    240 bool SkDeferredCanvas::rotate(SkScalar degrees) {
    241     drawingCanvas()->rotate(degrees);
    242     return this->INHERITED::rotate(degrees);
    243 }
    244 
    245 bool SkDeferredCanvas::skew(SkScalar sx, SkScalar sy) {
    246     drawingCanvas()->skew(sx, sy);
    247     return this->INHERITED::skew(sx, sy);
    248 }
    249 
    250 bool SkDeferredCanvas::concat(const SkMatrix& matrix) {
    251     drawingCanvas()->concat(matrix);
    252     return this->INHERITED::concat(matrix);
    253 }
    254 
    255 void SkDeferredCanvas::setMatrix(const SkMatrix& matrix) {
    256     drawingCanvas()->setMatrix(matrix);
    257     this->INHERITED::setMatrix(matrix);
    258 }
    259 
    260 bool 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 
    267 bool 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 
    274 bool SkDeferredCanvas::clipRegion(const SkRegion& deviceRgn,
    275                                   SkRegion::Op op) {
    276     drawingCanvas()->clipRegion(deviceRgn, op);
    277     return this->INHERITED::clipRegion(deviceRgn, op);
    278 }
    279 
    280 void SkDeferredCanvas::clear(SkColor color) {
    281     // purge pending commands
    282     if (fDeferredDrawing) {
    283         getDeferredDevice()->contentsCleared();
    284     }
    285 
    286     drawingCanvas()->clear(color);
    287 }
    288 
    289 void 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 
    298 void SkDeferredCanvas::drawPoints(PointMode mode, size_t count,
    299                                   const SkPoint pts[], const SkPaint& paint) {
    300     drawingCanvas()->drawPoints(mode, count, pts, paint);
    301 }
    302 
    303 void 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 
    312 void SkDeferredCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
    313     drawingCanvas()->drawPath(path, paint);
    314 }
    315 
    316 void 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 
    330 void 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 
    346 void 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 
    355 void 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 
    365 void 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 
    383 void 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 
    388 void SkDeferredCanvas::drawPosText(const void* text, size_t byteLength,
    389                                    const SkPoint pos[], const SkPaint& paint) {
    390     drawingCanvas()->drawPosText(text, byteLength, pos, paint);
    391 }
    392 
    393 void 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 
    399 void 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 
    408 void SkDeferredCanvas::drawPicture(SkPicture& picture) {
    409     drawingCanvas()->drawPicture(picture);
    410 }
    411 
    412 void 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 
    425 SkBounder* SkDeferredCanvas::setBounder(SkBounder* bounder) {
    426     drawingCanvas()->setBounder(bounder);
    427     return INHERITED::setBounder(bounder);
    428 }
    429 
    430 SkDrawFilter* SkDeferredCanvas::setDrawFilter(SkDrawFilter* filter) {
    431     drawingCanvas()->setDrawFilter(filter);
    432     return INHERITED::setDrawFilter(filter);
    433 }
    434 
    435 SkCanvas* SkDeferredCanvas::canvasForDrawIter() {
    436     return drawingCanvas();
    437 }
    438 
    439 // SkDeferredCanvas::DeferredDevice
    440 //------------------------------------
    441 
    442 SkDeferredCanvas::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 
    456 SkDeferredCanvas::DeferredDevice::~DeferredDevice() {
    457     SkSafeUnref(fImmediateCanvas);
    458     SkSafeUnref(fDeviceContext);
    459 }
    460 
    461 void SkDeferredCanvas::DeferredDevice::setDeviceContext(
    462     DeviceContext* deviceContext) {
    463     SkRefCnt_SafeAssign(fDeviceContext, deviceContext);
    464 }
    465 
    466 void 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 
    502 bool SkDeferredCanvas::DeferredDevice::isFreshFrame() {
    503     bool ret = fFreshFrame;
    504     fFreshFrame = false;
    505     return ret;
    506 }
    507 
    508 void 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 
    517 void SkDeferredCanvas::DeferredDevice::flush() {
    518     flushPending();
    519     fImmediateCanvas->flush();
    520 }
    521 
    522 void 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 
    533 uint32_t SkDeferredCanvas::DeferredDevice::getDeviceCapabilities() {
    534     return fImmediateDevice->getDeviceCapabilities();
    535 }
    536 
    537 int SkDeferredCanvas::DeferredDevice::width() const {
    538     return fImmediateDevice->width();
    539 }
    540 
    541 int SkDeferredCanvas::DeferredDevice::height() const {
    542     return fImmediateDevice->height();
    543 }
    544 
    545 SkGpuRenderTarget* SkDeferredCanvas::DeferredDevice::accessRenderTarget() {
    546     flushPending();
    547     return fImmediateDevice->accessRenderTarget();
    548 }
    549 
    550 void 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 
    572 const SkBitmap& SkDeferredCanvas::DeferredDevice::onAccessBitmap(SkBitmap*) {
    573     flushPending();
    574     return fImmediateDevice->accessBitmap(false);
    575 }
    576 
    577 SkDevice* 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 
    590 bool 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