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, nullptr)
     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, nullptr)
     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     if (buffer.isCrossProcess() && SkPicture::PictureIOSecurityPrecautionsEnabled()) {
     43         buffer.validate(!buffer.readBool());
     44     } else {
     45         if (buffer.readBool()) {
     46             picture.reset(SkPicture::CreateFromBuffer(buffer));
     47         }
     48     }
     49     buffer.readRect(&cropRect);
     50     PictureResolution pictureResolution;
     51     if (buffer.isVersionLT(SkReadBuffer::kPictureImageFilterResolution_Version)) {
     52         pictureResolution = kDeviceSpace_PictureResolution;
     53     } else {
     54         pictureResolution = (PictureResolution)buffer.readInt();
     55     }
     56 
     57     if (kLocalSpace_PictureResolution == pictureResolution) {
     58         //filterLevel is only serialized if pictureResolution is LocalSpace
     59         SkFilterQuality filterQuality;
     60         if (buffer.isVersionLT(SkReadBuffer::kPictureImageFilterLevel_Version)) {
     61             filterQuality = kLow_SkFilterQuality;
     62         } else {
     63             filterQuality = (SkFilterQuality)buffer.readInt();
     64         }
     65         return CreateForLocalSpace(picture, cropRect, filterQuality);
     66     }
     67     return Create(picture, cropRect);
     68 }
     69 
     70 void SkPictureImageFilter::flatten(SkWriteBuffer& buffer) const {
     71     if (buffer.isCrossProcess() && SkPicture::PictureIOSecurityPrecautionsEnabled()) {
     72         buffer.writeBool(false);
     73     } else {
     74         bool hasPicture = (fPicture != nullptr);
     75         buffer.writeBool(hasPicture);
     76         if (hasPicture) {
     77             fPicture->flatten(buffer);
     78         }
     79     }
     80     buffer.writeRect(fCropRect);
     81     buffer.writeInt(fPictureResolution);
     82     if (kLocalSpace_PictureResolution == fPictureResolution) {
     83         buffer.writeInt(fFilterQuality);
     84     }
     85 }
     86 
     87 bool SkPictureImageFilter::onFilterImageDeprecated(Proxy* proxy, const SkBitmap&,
     88                                                    const Context& ctx,
     89                                                    SkBitmap* result, SkIPoint* offset) const {
     90     if (!fPicture) {
     91         offset->fX = offset->fY = 0;
     92         return true;
     93     }
     94 
     95     SkRect floatBounds;
     96     ctx.ctm().mapRect(&floatBounds, fCropRect);
     97     SkIRect bounds = floatBounds.roundOut();
     98     if (!bounds.intersect(ctx.clipBounds())) {
     99         return false;
    100     }
    101 
    102     if (bounds.isEmpty()) {
    103         offset->fX = offset->fY = 0;
    104         return true;
    105     }
    106 
    107     SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
    108     if (nullptr == device.get()) {
    109         return false;
    110     }
    111 
    112     if (kDeviceSpace_PictureResolution == fPictureResolution ||
    113         0 == (ctx.ctm().getType() & ~SkMatrix::kTranslate_Mask)) {
    114         this->drawPictureAtDeviceResolution(device.get(), bounds, ctx);
    115     } else {
    116         this->drawPictureAtLocalResolution(proxy, device.get(), bounds, ctx);
    117     }
    118 
    119     *result = device.get()->accessBitmap(false);
    120     offset->fX = bounds.fLeft;
    121     offset->fY = bounds.fTop;
    122     return true;
    123 }
    124 
    125 void SkPictureImageFilter::drawPictureAtDeviceResolution(SkBaseDevice* device,
    126                                                          const SkIRect& deviceBounds,
    127                                                          const Context& ctx) const {
    128     SkCanvas canvas(device);
    129 
    130     canvas.translate(-SkIntToScalar(deviceBounds.fLeft), -SkIntToScalar(deviceBounds.fTop));
    131     canvas.concat(ctx.ctm());
    132     canvas.drawPicture(fPicture);
    133 }
    134 
    135 void SkPictureImageFilter::drawPictureAtLocalResolution(Proxy* proxy, SkBaseDevice* device,
    136                                                         const SkIRect& deviceBounds,
    137                                                         const Context& ctx) const {
    138     SkMatrix inverseCtm;
    139     if (!ctx.ctm().invert(&inverseCtm)) {
    140         return;
    141     }
    142 
    143     SkRect localBounds = SkRect::Make(ctx.clipBounds());
    144     inverseCtm.mapRect(&localBounds);
    145     if (!localBounds.intersect(fCropRect)) {
    146         return;
    147     }
    148     SkIRect localIBounds = localBounds.roundOut();
    149     SkAutoTUnref<SkBaseDevice> localDevice(proxy->createDevice(localIBounds.width(), localIBounds.height()));
    150 
    151     SkCanvas localCanvas(localDevice);
    152     localCanvas.translate(-SkIntToScalar(localIBounds.fLeft), -SkIntToScalar(localIBounds.fTop));
    153     localCanvas.drawPicture(fPicture);
    154 
    155     SkCanvas canvas(device);
    156 
    157     canvas.translate(-SkIntToScalar(deviceBounds.fLeft), -SkIntToScalar(deviceBounds.fTop));
    158     canvas.concat(ctx.ctm());
    159     SkPaint paint;
    160     paint.setFilterQuality(fFilterQuality);
    161     canvas.drawBitmap(localDevice.get()->accessBitmap(false), SkIntToScalar(localIBounds.fLeft),
    162                       SkIntToScalar(localIBounds.fTop), &paint);
    163 }
    164 
    165 #ifndef SK_IGNORE_TO_STRING
    166 void SkPictureImageFilter::toString(SkString* str) const {
    167     str->appendf("SkPictureImageFilter: (");
    168     str->appendf("crop: (%f,%f,%f,%f) ",
    169                  fCropRect.fLeft, fCropRect.fTop, fCropRect.fRight, fCropRect.fBottom);
    170     if (fPicture) {
    171         str->appendf("picture: (%f,%f,%f,%f)",
    172                      fPicture->cullRect().fLeft, fPicture->cullRect().fTop,
    173                      fPicture->cullRect().fRight, fPicture->cullRect().fBottom);
    174     }
    175     str->append(")");
    176 }
    177 #endif
    178