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 "SkImageSource.h"
     14 #include "SkReadBuffer.h"
     15 #include "SkSpecialImage.h"
     16 #include "SkSpecialSurface.h"
     17 #include "SkWriteBuffer.h"
     18 #include "SkValidationUtils.h"
     19 
     20 sk_sp<SkImageFilter> SkPictureImageFilter::Make(sk_sp<SkPicture> picture) {
     21     return sk_sp<SkImageFilter>(new SkPictureImageFilter(std::move(picture)));
     22 }
     23 
     24 sk_sp<SkImageFilter> SkPictureImageFilter::Make(sk_sp<SkPicture> picture,
     25                                                 const SkRect& cropRect) {
     26     return sk_sp<SkImageFilter>(new SkPictureImageFilter(std::move(picture), cropRect, nullptr));
     27 }
     28 
     29 SkPictureImageFilter::SkPictureImageFilter(sk_sp<SkPicture> picture)
     30     : INHERITED(nullptr, 0, nullptr)
     31     , fPicture(std::move(picture))
     32     , fCropRect(fPicture ? fPicture->cullRect() : SkRect::MakeEmpty()) {
     33 }
     34 
     35 SkPictureImageFilter::SkPictureImageFilter(sk_sp<SkPicture> picture, const SkRect& cropRect,
     36                                            sk_sp<SkColorSpace> colorSpace)
     37     : INHERITED(nullptr, 0, nullptr)
     38     , fPicture(std::move(picture))
     39     , fCropRect(cropRect)
     40     , fColorSpace(std::move(colorSpace)) {
     41 }
     42 
     43 enum PictureResolution {
     44     kDeviceSpace_PictureResolution,
     45     kLocalSpace_PictureResolution
     46 };
     47 static sk_sp<SkImageFilter> make_localspace_filter(sk_sp<SkPicture> pic, const SkRect& cropRect,
     48                                                    SkFilterQuality fq) {
     49     SkISize dim = { SkScalarRoundToInt(cropRect.width()), SkScalarRoundToInt(cropRect.height()) };
     50     auto img = SkImage::MakeFromPicture(std::move(pic), dim, nullptr, nullptr,
     51                                         SkImage::BitDepth::kU8, SkColorSpace::MakeSRGB());
     52     return SkImageSource::Make(img, cropRect, cropRect, fq);
     53 }
     54 
     55 sk_sp<SkFlattenable> SkPictureImageFilter::CreateProc(SkReadBuffer& buffer) {
     56     sk_sp<SkPicture> picture;
     57     SkRect cropRect;
     58 
     59     if (buffer.readBool()) {
     60         picture = SkPicture::MakeFromBuffer(buffer);
     61     }
     62     buffer.readRect(&cropRect);
     63 
     64     if (buffer.isVersionLT(SkReadBuffer::kRemovePictureImageFilterLocalSpace)) {
     65         PictureResolution pictureResolution = buffer.checkRange<PictureResolution>(
     66             kDeviceSpace_PictureResolution, kLocalSpace_PictureResolution);
     67         if (kLocalSpace_PictureResolution == pictureResolution) {
     68             return make_localspace_filter(std::move(picture), cropRect,
     69                                           buffer.checkFilterQuality());
     70         }
     71     }
     72     return sk_sp<SkImageFilter>(new SkPictureImageFilter(picture, cropRect, nullptr));
     73 }
     74 
     75 void SkPictureImageFilter::flatten(SkWriteBuffer& buffer) const {
     76     bool hasPicture = (fPicture != nullptr);
     77     buffer.writeBool(hasPicture);
     78     if (hasPicture) {
     79         fPicture->flatten(buffer);
     80     }
     81     buffer.writeRect(fCropRect);
     82 }
     83 
     84 sk_sp<SkSpecialImage> SkPictureImageFilter::onFilterImage(SkSpecialImage* source,
     85                                                           const Context& ctx,
     86                                                           SkIPoint* offset) const {
     87     if (!fPicture) {
     88         return nullptr;
     89     }
     90 
     91     SkRect floatBounds;
     92     ctx.ctm().mapRect(&floatBounds, fCropRect);
     93     SkIRect bounds = floatBounds.roundOut();
     94     if (!bounds.intersect(ctx.clipBounds())) {
     95         return nullptr;
     96     }
     97 
     98     SkASSERT(!bounds.isEmpty());
     99 
    100     sk_sp<SkSpecialSurface> surf(source->makeSurface(ctx.outputProperties(), bounds.size()));
    101     if (!surf) {
    102         return nullptr;
    103     }
    104 
    105     SkCanvas* canvas = surf->getCanvas();
    106     SkASSERT(canvas);
    107     canvas->clear(0x0);
    108 
    109     std::unique_ptr<SkCanvas> xformCanvas;
    110     if (fColorSpace) {
    111         // Only non-null in the case where onMakeColorSpace() was called.  This instructs
    112         // us to do the color space xform on playback.
    113         xformCanvas = SkCreateColorSpaceXformCanvas(canvas, fColorSpace);
    114         canvas = xformCanvas.get();
    115     }
    116     canvas->translate(-SkIntToScalar(bounds.fLeft), -SkIntToScalar(bounds.fTop));
    117     canvas->concat(ctx.ctm());
    118     canvas->drawPicture(fPicture);
    119 
    120     offset->fX = bounds.fLeft;
    121     offset->fY = bounds.fTop;
    122     return surf->makeImageSnapshot();
    123 }
    124 
    125 sk_sp<SkImageFilter> SkPictureImageFilter::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
    126     sk_sp<SkColorSpace> dstCS = xformer->dst();
    127     if (SkColorSpace::Equals(dstCS.get(), fColorSpace.get())) {
    128         return this->refMe();
    129     }
    130 
    131     return sk_sp<SkImageFilter>(new SkPictureImageFilter(fPicture, fCropRect, std::move(dstCS)));
    132 }
    133 
    134 #ifndef SK_IGNORE_TO_STRING
    135 void SkPictureImageFilter::toString(SkString* str) const {
    136     str->appendf("SkPictureImageFilter: (");
    137     str->appendf("crop: (%f,%f,%f,%f) ",
    138                  fCropRect.fLeft, fCropRect.fTop, fCropRect.fRight, fCropRect.fBottom);
    139     if (fPicture) {
    140         str->appendf("picture: (%f,%f,%f,%f)",
    141                      fPicture->cullRect().fLeft, fPicture->cullRect().fTop,
    142                      fPicture->cullRect().fRight, fPicture->cullRect().fBottom);
    143     }
    144     str->append(")");
    145 }
    146 #endif
    147