Home | History | Annotate | Download | only in effects
      1 /*
      2  * Copyright 2013 The Android Open Source Project
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkPictureImageFilter.h"
      9 #include "SkDevice.h"
     10 #include "SkCanvas.h"
     11 #include "SkReadBuffer.h"
     12 #include "SkSurfaceProps.h"
     13 #include "SkWriteBuffer.h"
     14 #include "SkValidationUtils.h"
     15 
     16 SkPictureImageFilter::SkPictureImageFilter(const SkPicture* picture)
     17     : INHERITED(0, 0, NULL)
     18     , fPicture(SkSafeRef(picture))
     19     , fCropRect(picture ? picture->cullRect() : SkRect::MakeEmpty())
     20     , fPictureResolution(kDeviceSpace_PictureResolution)
     21     , fFilterQuality(kLow_SkFilterQuality) {
     22 }
     23 
     24 SkPictureImageFilter::SkPictureImageFilter(const SkPicture* picture, const SkRect& cropRect,
     25                                            PictureResolution pictureResolution,
     26                                            SkFilterQuality filterQuality)
     27     : INHERITED(0, 0, NULL)
     28     , fPicture(SkSafeRef(picture))
     29     , fCropRect(cropRect)
     30     , fPictureResolution(pictureResolution)
     31     , fFilterQuality(filterQuality) {
     32 }
     33 
     34 SkPictureImageFilter::~SkPictureImageFilter() {
     35     SkSafeUnref(fPicture);
     36 }
     37 
     38 SkFlattenable* SkPictureImageFilter::CreateProc(SkReadBuffer& buffer) {
     39     SkAutoTUnref<SkPicture> picture;
     40     SkRect cropRect;
     41 
     42 #ifdef SK_DISALLOW_CROSSPROCESS_PICTUREIMAGEFILTERS
     43     if (buffer.isCrossProcess()) {
     44         buffer.validate(!buffer.readBool());
     45     } else
     46 #endif
     47     {
     48         if (buffer.readBool()) {
     49             picture.reset(SkPicture::CreateFromBuffer(buffer));
     50         }
     51     }
     52     buffer.readRect(&cropRect);
     53     PictureResolution pictureResolution;
     54     if (buffer.isVersionLT(SkReadBuffer::kPictureImageFilterResolution_Version)) {
     55         pictureResolution = kDeviceSpace_PictureResolution;
     56     } else {
     57         pictureResolution = (PictureResolution)buffer.readInt();
     58     }
     59 
     60     if (kLocalSpace_PictureResolution == pictureResolution) {
     61         //filterLevel is only serialized if pictureResolution is LocalSpace
     62         SkFilterQuality filterQuality;
     63         if (buffer.isVersionLT(SkReadBuffer::kPictureImageFilterLevel_Version)) {
     64             filterQuality = kLow_SkFilterQuality;
     65         } else {
     66             filterQuality = (SkFilterQuality)buffer.readInt();
     67         }
     68         return CreateForLocalSpace(picture, cropRect, filterQuality);
     69     }
     70     return Create(picture, cropRect);
     71 }
     72 
     73 void SkPictureImageFilter::flatten(SkWriteBuffer& buffer) const {
     74 #ifdef SK_DISALLOW_CROSSPROCESS_PICTUREIMAGEFILTERS
     75     if (buffer.isCrossProcess()) {
     76         buffer.writeBool(false);
     77     } else
     78 #endif
     79     {
     80         bool hasPicture = (fPicture != NULL);
     81         buffer.writeBool(hasPicture);
     82         if (hasPicture) {
     83             fPicture->flatten(buffer);
     84         }
     85     }
     86     buffer.writeRect(fCropRect);
     87     buffer.writeInt(fPictureResolution);
     88     if (kLocalSpace_PictureResolution == fPictureResolution) {
     89         buffer.writeInt(fFilterQuality);
     90     }
     91 }
     92 
     93 bool SkPictureImageFilter::onFilterImage(Proxy* proxy, const SkBitmap&, const Context& ctx,
     94                                          SkBitmap* result, SkIPoint* offset) const {
     95     if (!fPicture) {
     96         offset->fX = offset->fY = 0;
     97         return true;
     98     }
     99 
    100     SkRect floatBounds;
    101     ctx.ctm().mapRect(&floatBounds, fCropRect);
    102     SkIRect bounds = floatBounds.roundOut();
    103     if (!bounds.intersect(ctx.clipBounds())) {
    104         return false;
    105     }
    106 
    107     if (bounds.isEmpty()) {
    108         offset->fX = offset->fY = 0;
    109         return true;
    110     }
    111 
    112     SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
    113     if (NULL == device.get()) {
    114         return false;
    115     }
    116 
    117     if (kDeviceSpace_PictureResolution == fPictureResolution ||
    118         0 == (ctx.ctm().getType() & ~SkMatrix::kTranslate_Mask)) {
    119         drawPictureAtDeviceResolution(proxy, device.get(), bounds, ctx);
    120     } else {
    121         drawPictureAtLocalResolution(proxy, device.get(), bounds, ctx);
    122     }
    123 
    124     *result = device.get()->accessBitmap(false);
    125     offset->fX = bounds.fLeft;
    126     offset->fY = bounds.fTop;
    127     return true;
    128 }
    129 
    130 void SkPictureImageFilter::drawPictureAtDeviceResolution(Proxy* proxy, SkBaseDevice* device,
    131                                                          const SkIRect& deviceBounds,
    132                                                          const Context& ctx) const {
    133     // Pass explicit surface props, as the simplified canvas constructor discards device properties.
    134     // FIXME: switch back to the public constructor (and unfriend) after
    135     //        https://code.google.com/p/skia/issues/detail?id=3142 is fixed.
    136     SkCanvas canvas(device, proxy->surfaceProps(), SkCanvas::kDefault_InitFlags);
    137 
    138     canvas.translate(-SkIntToScalar(deviceBounds.fLeft), -SkIntToScalar(deviceBounds.fTop));
    139     canvas.concat(ctx.ctm());
    140     canvas.drawPicture(fPicture);
    141 }
    142 
    143 void SkPictureImageFilter::drawPictureAtLocalResolution(Proxy* proxy, SkBaseDevice* device,
    144                                                         const SkIRect& deviceBounds,
    145                                                         const Context& ctx) const {
    146     SkMatrix inverseCtm;
    147     if (!ctx.ctm().invert(&inverseCtm))
    148         return;
    149     SkRect localBounds = SkRect::Make(ctx.clipBounds());
    150     inverseCtm.mapRect(&localBounds);
    151     if (!localBounds.intersect(fCropRect))
    152         return;
    153     SkIRect localIBounds = localBounds.roundOut();
    154     SkAutoTUnref<SkBaseDevice> localDevice(proxy->createDevice(localIBounds.width(), localIBounds.height()));
    155 
    156     // Pass explicit surface props, as the simplified canvas constructor discards device properties.
    157     // FIXME: switch back to the public constructor (and unfriend) after
    158     //        https://code.google.com/p/skia/issues/detail?id=3142 is fixed.
    159     SkCanvas localCanvas(localDevice, proxy->surfaceProps(), SkCanvas::kDefault_InitFlags);
    160     localCanvas.translate(-SkIntToScalar(localIBounds.fLeft), -SkIntToScalar(localIBounds.fTop));
    161     localCanvas.drawPicture(fPicture);
    162 
    163     // Pass explicit surface props, as the simplified canvas constructor discards device properties.
    164     // FIXME: switch back to the public constructor (and unfriend) after
    165     //        https://code.google.com/p/skia/issues/detail?id=3142 is fixed.
    166     SkCanvas canvas(device, proxy->surfaceProps(), SkCanvas::kDefault_InitFlags);
    167 
    168     canvas.translate(-SkIntToScalar(deviceBounds.fLeft), -SkIntToScalar(deviceBounds.fTop));
    169     canvas.concat(ctx.ctm());
    170     SkPaint paint;
    171     paint.setFilterQuality(fFilterQuality);
    172     canvas.drawBitmap(localDevice.get()->accessBitmap(false), SkIntToScalar(localIBounds.fLeft),
    173                       SkIntToScalar(localIBounds.fTop), &paint);
    174     //canvas.drawPicture(fPicture);
    175 }
    176 
    177 #ifndef SK_IGNORE_TO_STRING
    178 void SkPictureImageFilter::toString(SkString* str) const {
    179     str->appendf("SkPictureImageFilter: (");
    180     str->appendf("crop: (%f,%f,%f,%f) ",
    181                  fCropRect.fLeft, fCropRect.fTop, fCropRect.fRight, fCropRect.fBottom);
    182     if (fPicture) {
    183         str->appendf("picture: (%f,%f,%f,%f)",
    184                      fPicture->cullRect().fLeft, fPicture->cullRect().fTop,
    185                      fPicture->cullRect().fRight, fPicture->cullRect().fBottom);
    186     }
    187     str->append(")");
    188 }
    189 #endif
    190