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 
     10 #include "SkCanvas.h"
     11 #include "SkColorSpaceXformCanvas.h"
     12 #include "SkColorSpaceXformer.h"
     13 #include "SkReadBuffer.h"
     14 #include "SkSpecialImage.h"
     15 #include "SkSpecialSurface.h"
     16 #include "SkWriteBuffer.h"
     17 #include "SkValidationUtils.h"
     18 
     19 sk_sp<SkImageFilter> SkPictureImageFilter::Make(sk_sp<SkPicture> picture) {
     20     return sk_sp<SkImageFilter>(new SkPictureImageFilter(std::move(picture)));
     21 }
     22 
     23 sk_sp<SkImageFilter> SkPictureImageFilter::Make(sk_sp<SkPicture> picture,
     24                                                 const SkRect& cropRect) {
     25     return sk_sp<SkImageFilter>(new SkPictureImageFilter(std::move(picture),
     26                                                          cropRect,
     27                                                          kDeviceSpace_PictureResolution,
     28                                                          kLow_SkFilterQuality,
     29                                                          nullptr));
     30 }
     31 
     32 sk_sp<SkImageFilter> SkPictureImageFilter::MakeForLocalSpace(sk_sp<SkPicture> picture,
     33                                                              const SkRect& cropRect,
     34                                                              SkFilterQuality filterQuality) {
     35     return sk_sp<SkImageFilter>(new SkPictureImageFilter(std::move(picture),
     36                                                          cropRect,
     37                                                          kLocalSpace_PictureResolution,
     38                                                          filterQuality,
     39                                                          nullptr));
     40 }
     41 
     42 SkPictureImageFilter::SkPictureImageFilter(sk_sp<SkPicture> picture)
     43     : INHERITED(nullptr, 0, nullptr)
     44     , fPicture(std::move(picture))
     45     , fCropRect(fPicture ? fPicture->cullRect() : SkRect::MakeEmpty())
     46     , fPictureResolution(kDeviceSpace_PictureResolution)
     47     , fFilterQuality(kLow_SkFilterQuality) {
     48 }
     49 
     50 SkPictureImageFilter::SkPictureImageFilter(sk_sp<SkPicture> picture, const SkRect& cropRect,
     51                                            PictureResolution pictureResolution,
     52                                            SkFilterQuality filterQuality,
     53                                            sk_sp<SkColorSpace> colorSpace)
     54     : INHERITED(nullptr, 0, nullptr)
     55     , fPicture(std::move(picture))
     56     , fCropRect(cropRect)
     57     , fPictureResolution(pictureResolution)
     58     , fFilterQuality(filterQuality)
     59     , fColorSpace(std::move(colorSpace)) {
     60 }
     61 
     62 sk_sp<SkFlattenable> SkPictureImageFilter::CreateProc(SkReadBuffer& buffer) {
     63     sk_sp<SkPicture> picture;
     64     SkRect cropRect;
     65 
     66     if (buffer.isCrossProcess() && SkPicture::PictureIOSecurityPrecautionsEnabled()) {
     67         buffer.validate(!buffer.readBool());
     68     } else {
     69         if (buffer.readBool()) {
     70             picture = SkPicture::MakeFromBuffer(buffer);
     71         }
     72     }
     73     buffer.readRect(&cropRect);
     74     PictureResolution pictureResolution = (PictureResolution)buffer.readInt();
     75 
     76     if (kLocalSpace_PictureResolution == pictureResolution) {
     77         //filterLevel is only serialized if pictureResolution is LocalSpace
     78         SkFilterQuality filterQuality = (SkFilterQuality)buffer.readInt();
     79         return MakeForLocalSpace(picture, cropRect, filterQuality);
     80     }
     81     return Make(picture, cropRect);
     82 }
     83 
     84 void SkPictureImageFilter::flatten(SkWriteBuffer& buffer) const {
     85     if (buffer.isCrossProcess() && SkPicture::PictureIOSecurityPrecautionsEnabled()) {
     86         buffer.writeBool(false);
     87     } else {
     88         bool hasPicture = (fPicture != nullptr);
     89         buffer.writeBool(hasPicture);
     90         if (hasPicture) {
     91             fPicture->flatten(buffer);
     92         }
     93     }
     94     buffer.writeRect(fCropRect);
     95     buffer.writeInt(fPictureResolution);
     96     if (kLocalSpace_PictureResolution == fPictureResolution) {
     97         buffer.writeInt(fFilterQuality);
     98     }
     99 }
    100 
    101 sk_sp<SkSpecialImage> SkPictureImageFilter::onFilterImage(SkSpecialImage* source,
    102                                                           const Context& ctx,
    103                                                           SkIPoint* offset) const {
    104     if (!fPicture) {
    105         return nullptr;
    106     }
    107 
    108     SkRect floatBounds;
    109     ctx.ctm().mapRect(&floatBounds, fCropRect);
    110     SkIRect bounds = floatBounds.roundOut();
    111     if (!bounds.intersect(ctx.clipBounds())) {
    112         return nullptr;
    113     }
    114 
    115     SkASSERT(!bounds.isEmpty());
    116 
    117     sk_sp<SkSpecialSurface> surf(source->makeSurface(ctx.outputProperties(), bounds.size()));
    118     if (!surf) {
    119         return nullptr;
    120     }
    121 
    122     SkCanvas* canvas = surf->getCanvas();
    123     SkASSERT(canvas);
    124     canvas->clear(0x0);
    125 
    126     if (kDeviceSpace_PictureResolution == fPictureResolution ||
    127         0 == (ctx.ctm().getType() & ~SkMatrix::kTranslate_Mask)) {
    128         this->drawPictureAtDeviceResolution(canvas, bounds, ctx);
    129     } else {
    130         this->drawPictureAtLocalResolution(source, canvas, bounds, ctx);
    131     }
    132 
    133     offset->fX = bounds.fLeft;
    134     offset->fY = bounds.fTop;
    135     return surf->makeImageSnapshot();
    136 }
    137 
    138 sk_sp<SkImageFilter> SkPictureImageFilter::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
    139     sk_sp<SkColorSpace> dstCS = xformer->dst();
    140     if (SkColorSpace::Equals(dstCS.get(), fColorSpace.get())) {
    141         return this->refMe();
    142     }
    143 
    144     return sk_sp<SkImageFilter>(new SkPictureImageFilter(fPicture, fCropRect, fPictureResolution,
    145             fFilterQuality, std::move(dstCS)));
    146 }
    147 
    148 void SkPictureImageFilter::drawPictureAtDeviceResolution(SkCanvas* canvas,
    149                                                          const SkIRect& deviceBounds,
    150                                                          const Context& ctx) const {
    151     std::unique_ptr<SkCanvas> xformCanvas = nullptr;
    152     if (fColorSpace) {
    153         // Only non-null in the case where onMakeColorSpace() was called.  This instructs
    154         // us to do the color space xform on playback.
    155         xformCanvas = SkCreateColorSpaceXformCanvas(canvas, fColorSpace);
    156         canvas = xformCanvas.get();
    157     }
    158     canvas->translate(-SkIntToScalar(deviceBounds.fLeft), -SkIntToScalar(deviceBounds.fTop));
    159     canvas->concat(ctx.ctm());
    160     canvas->drawPicture(fPicture);
    161 }
    162 
    163 void SkPictureImageFilter::drawPictureAtLocalResolution(SkSpecialImage* source,
    164                                                         SkCanvas* canvas,
    165                                                         const SkIRect& deviceBounds,
    166                                                         const Context& ctx) const {
    167     SkMatrix inverseCtm;
    168     if (!ctx.ctm().invert(&inverseCtm)) {
    169         return;
    170     }
    171 
    172     SkRect localBounds = SkRect::Make(ctx.clipBounds());
    173     inverseCtm.mapRect(&localBounds);
    174     if (!localBounds.intersect(fCropRect)) {
    175         return;
    176     }
    177     SkIRect localIBounds = localBounds.roundOut();
    178 
    179     sk_sp<SkSpecialImage> localImg;
    180     {
    181         sk_sp<SkSpecialSurface> localSurface(source->makeSurface(ctx.outputProperties(),
    182                                                                  localIBounds.size()));
    183         if (!localSurface) {
    184             return;
    185         }
    186 
    187         SkCanvas* localCanvas = localSurface->getCanvas();
    188         SkASSERT(localCanvas);
    189         std::unique_ptr<SkCanvas> xformCanvas = nullptr;
    190         if (fColorSpace) {
    191             // Only non-null in the case where onMakeColorSpace() was called.  This instructs
    192             // us to do the color space xform on playback.
    193             xformCanvas = SkCreateColorSpaceXformCanvas(localCanvas, fColorSpace);
    194             localCanvas = xformCanvas.get();
    195         }
    196 
    197         localCanvas->clear(0x0);
    198 
    199         localCanvas->translate(-SkIntToScalar(localIBounds.fLeft),
    200                                -SkIntToScalar(localIBounds.fTop));
    201         localCanvas->drawPicture(fPicture);
    202 
    203         localImg = localSurface->makeImageSnapshot();
    204         SkASSERT(localImg);
    205     }
    206 
    207     {
    208         canvas->translate(-SkIntToScalar(deviceBounds.fLeft), -SkIntToScalar(deviceBounds.fTop));
    209         canvas->concat(ctx.ctm());
    210         SkPaint paint;
    211         paint.setFilterQuality(fFilterQuality);
    212 
    213         localImg->draw(canvas,
    214                        SkIntToScalar(localIBounds.fLeft),
    215                        SkIntToScalar(localIBounds.fTop),
    216                        &paint);
    217     }
    218 }
    219 
    220 #ifndef SK_IGNORE_TO_STRING
    221 void SkPictureImageFilter::toString(SkString* str) const {
    222     str->appendf("SkPictureImageFilter: (");
    223     str->appendf("crop: (%f,%f,%f,%f) ",
    224                  fCropRect.fLeft, fCropRect.fTop, fCropRect.fRight, fCropRect.fBottom);
    225     if (fPicture) {
    226         str->appendf("picture: (%f,%f,%f,%f)",
    227                      fPicture->cullRect().fLeft, fPicture->cullRect().fTop,
    228                      fPicture->cullRect().fRight, fPicture->cullRect().fBottom);
    229     }
    230     str->append(")");
    231 }
    232 #endif
    233