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 "include/effects/SkImageFilters.h"
9
10 #include "include/core/SkFlattenable.h"
11 #include "include/core/SkImageFilter.h"
12 #include "include/core/SkPicture.h"
13 #include "include/core/SkRect.h"
14 #include "include/core/SkRefCnt.h"
15 #include "include/core/SkTypes.h"
16 #include "include/private/base/SkTo.h"
17 #include "src/core/SkImageFilterTypes.h"
18 #include "src/core/SkImageFilter_Base.h"
19 #include "src/core/SkPicturePriv.h"
20 #include "src/core/SkReadBuffer.h"
21 #include "src/core/SkWriteBuffer.h"
22
23 #include <optional>
24 #include <utility>
25
26 namespace {
27
28 class SkPictureImageFilter final : public SkImageFilter_Base {
29 public:
SkPictureImageFilter(sk_sp<SkPicture> picture,const SkRect & cullRect)30 SkPictureImageFilter(sk_sp<SkPicture> picture, const SkRect& cullRect)
31 : SkImageFilter_Base(nullptr, 0)
32 , fPicture(std::move(picture))
33 , fCullRect(cullRect) {
34 // The external cullrect should already have been intersected with the internal cull rect
35 SkASSERT(fPicture && fPicture->cullRect().contains(cullRect));
36 }
37
computeFastBounds(const SkRect &) const38 SkRect computeFastBounds(const SkRect&) const override { return SkRect(fCullRect); }
39
40 protected:
41 void flatten(SkWriteBuffer&) const override;
42
43 private:
44 friend void ::SkRegisterPictureImageFilterFlattenable();
SK_FLATTENABLE_HOOKS(SkPictureImageFilter)45 SK_FLATTENABLE_HOOKS(SkPictureImageFilter)
46
47 MatrixCapability onGetCTMCapability() const override { return MatrixCapability::kComplex; }
48
49 skif::FilterResult onFilterImage(const skif::Context& ctx) const override;
50
51 skif::LayerSpace<SkIRect> onGetInputLayerBounds(
52 const skif::Mapping& mapping,
53 const skif::LayerSpace<SkIRect>& desiredOutput,
54 std::optional<skif::LayerSpace<SkIRect>> contentBounds) const override;
55
56 std::optional<skif::LayerSpace<SkIRect>> onGetOutputLayerBounds(
57 const skif::Mapping& mapping,
58 std::optional<skif::LayerSpace<SkIRect>> contentBounds) const override;
59
60 sk_sp<SkPicture> fPicture;
61 skif::ParameterSpace<SkRect> fCullRect;
62 };
63
64 } // end namespace
65
Picture(sk_sp<SkPicture> pic,const SkRect & targetRect)66 sk_sp<SkImageFilter> SkImageFilters::Picture(sk_sp<SkPicture> pic, const SkRect& targetRect) {
67 if (pic) {
68 SkRect cullRect = pic->cullRect();
69 if (cullRect.intersect(targetRect)) {
70 return sk_sp<SkImageFilter>(new SkPictureImageFilter(std::move(pic), cullRect));
71 }
72 }
73 return SkImageFilters::Empty();
74 }
75
SkRegisterPictureImageFilterFlattenable()76 void SkRegisterPictureImageFilterFlattenable() {
77 SK_REGISTER_FLATTENABLE(SkPictureImageFilter);
78 // TODO (michaelludwig) - Remove after grace period for SKPs to stop using old name
79 SkFlattenable::Register("SkPictureImageFilterImpl", SkPictureImageFilter::CreateProc);
80 }
81
CreateProc(SkReadBuffer & buffer)82 sk_sp<SkFlattenable> SkPictureImageFilter::CreateProc(SkReadBuffer& buffer) {
83 sk_sp<SkPicture> picture;
84 if (buffer.readBool()) {
85 picture = SkPicturePriv::MakeFromBuffer(buffer);
86 }
87
88 SkRect cullRect;
89 buffer.readRect(&cullRect);
90 return SkImageFilters::Picture(std::move(picture), cullRect);
91 }
92
flatten(SkWriteBuffer & buffer) const93 void SkPictureImageFilter::flatten(SkWriteBuffer& buffer) const {
94 buffer.writeBool(SkToBool(fPicture));
95 if (fPicture) {
96 SkPicturePriv::Flatten(fPicture, buffer);
97 }
98 buffer.writeRect(SkRect(fCullRect));
99 }
100
101 ///////////////////////////////////////////////////////////////////////////////////////////////////
102
onFilterImage(const skif::Context & ctx) const103 skif::FilterResult SkPictureImageFilter::onFilterImage(const skif::Context& ctx) const {
104 return skif::FilterResult::MakeFromPicture(ctx, fPicture, fCullRect);
105 }
106
onGetInputLayerBounds(const skif::Mapping &,const skif::LayerSpace<SkIRect> &,std::optional<skif::LayerSpace<SkIRect>>) const107 skif::LayerSpace<SkIRect> SkPictureImageFilter::onGetInputLayerBounds(
108 const skif::Mapping&,
109 const skif::LayerSpace<SkIRect>&,
110 std::optional<skif::LayerSpace<SkIRect>>) const {
111 // This is a leaf filter, it requires no input and no further recursion
112 return skif::LayerSpace<SkIRect>::Empty();
113 }
114
onGetOutputLayerBounds(const skif::Mapping & mapping,std::optional<skif::LayerSpace<SkIRect>>) const115 std::optional<skif::LayerSpace<SkIRect>> SkPictureImageFilter::onGetOutputLayerBounds(
116 const skif::Mapping& mapping,
117 std::optional<skif::LayerSpace<SkIRect>>) const {
118 // The output is the transformed bounds of the picture.
119 return mapping.paramToLayer(fCullRect).roundOut();
120 }
121