blob: 3e6ec70565942e4873e6bb68fb7f1d5d9995546f [file] [log] [blame]
/*
* Copyright 2013 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/effects/SkImageFilters.h"
#include "include/core/SkFlattenable.h"
#include "include/core/SkImageFilter.h"
#include "include/core/SkPicture.h"
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkTypes.h"
#include "include/private/base/SkTo.h"
#include "src/core/SkImageFilterTypes.h"
#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkPicturePriv.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkWriteBuffer.h"
#include <utility>
namespace {
class SkPictureImageFilter final : public SkImageFilter_Base {
public:
SkPictureImageFilter(sk_sp<SkPicture> picture, const SkRect& cullRect)
: SkImageFilter_Base(nullptr, 0, nullptr)
, fPicture(std::move(picture))
, fCullRect(cullRect) {
// The external cullrect should already have been intersected with the internal cull rect
SkASSERT((!fPicture && cullRect.isEmpty()) ||
(fPicture && fPicture->cullRect().contains(cullRect)));
}
SkRect computeFastBounds(const SkRect&) const override { return SkRect(fCullRect); }
protected:
void flatten(SkWriteBuffer&) const override;
private:
friend void ::SkRegisterPictureImageFilterFlattenable();
SK_FLATTENABLE_HOOKS(SkPictureImageFilter)
MatrixCapability onGetCTMCapability() const override { return MatrixCapability::kComplex; }
skif::FilterResult onFilterImage(const skif::Context& ctx) const override;
skif::LayerSpace<SkIRect> onGetInputLayerBounds(
const skif::Mapping&,
const skif::LayerSpace<SkIRect>& desiredOutput,
const skif::LayerSpace<SkIRect>& contentBounds) const override;
skif::LayerSpace<SkIRect> onGetOutputLayerBounds(
const skif::Mapping&,
const skif::LayerSpace<SkIRect>& contentBounds) const override;
sk_sp<SkPicture> fPicture;
skif::ParameterSpace<SkRect> fCullRect;
};
} // end namespace
sk_sp<SkImageFilter> SkImageFilters::Picture(sk_sp<SkPicture> pic, const SkRect& targetRect) {
if (pic) {
SkRect cullRect = pic->cullRect();
if (cullRect.intersect(targetRect)) {
return sk_sp<SkImageFilter>(new SkPictureImageFilter(std::move(pic), cullRect));
}
}
// Will always produce an empty image
return sk_sp<SkImageFilter>(new SkPictureImageFilter(nullptr, SkRect::MakeEmpty()));
}
void SkRegisterPictureImageFilterFlattenable() {
SK_REGISTER_FLATTENABLE(SkPictureImageFilter);
// TODO (michaelludwig) - Remove after grace period for SKPs to stop using old name
SkFlattenable::Register("SkPictureImageFilterImpl", SkPictureImageFilter::CreateProc);
}
sk_sp<SkFlattenable> SkPictureImageFilter::CreateProc(SkReadBuffer& buffer) {
sk_sp<SkPicture> picture;
if (buffer.readBool()) {
picture = SkPicturePriv::MakeFromBuffer(buffer);
}
SkRect cullRect;
buffer.readRect(&cullRect);
return SkImageFilters::Picture(std::move(picture), cullRect);
}
void SkPictureImageFilter::flatten(SkWriteBuffer& buffer) const {
buffer.writeBool(SkToBool(fPicture));
if (fPicture) {
SkPicturePriv::Flatten(fPicture, buffer);
}
buffer.writeRect(SkRect(fCullRect));
}
///////////////////////////////////////////////////////////////////////////////////////////////////
skif::FilterResult SkPictureImageFilter::onFilterImage(const skif::Context& ctx) const {
return skif::FilterResult::MakeFromPicture(ctx, fPicture, fCullRect);
}
skif::LayerSpace<SkIRect> SkPictureImageFilter::onGetInputLayerBounds(
const skif::Mapping&,
const skif::LayerSpace<SkIRect>&,
const skif::LayerSpace<SkIRect>&) const {
// This is a leaf filter, it requires no input and no further recursion
return skif::LayerSpace<SkIRect>::Empty();
}
skif::LayerSpace<SkIRect> SkPictureImageFilter::onGetOutputLayerBounds(
const skif::Mapping& mapping,
const skif::LayerSpace<SkIRect>&) const {
if (fPicture) {
// The output is the transformed bounds of the picture.
return mapping.paramToLayer(fCullRect).roundOut();
} else {
// An empty picture is fully transparent
return skif::LayerSpace<SkIRect>::Empty();
}
}