• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015 Google Inc.
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/SkImage.h"
12 #include "include/core/SkImageFilter.h"
13 #include "include/core/SkMatrix.h"
14 #include "include/core/SkRect.h"
15 #include "include/core/SkRefCnt.h"
16 #include "include/core/SkSamplingOptions.h"
17 #include "include/private/base/SkAssert.h"
18 #include "src/core/SkImageFilterTypes.h"
19 #include "src/core/SkImageFilter_Base.h"
20 #include "src/core/SkPicturePriv.h"
21 #include "src/core/SkReadBuffer.h"
22 #include "src/core/SkSamplingPriv.h"
23 #include "src/core/SkWriteBuffer.h"
24 
25 #include <optional>
26 #include <utility>
27 
28 namespace {
29 
30 class SkImageImageFilter final : public SkImageFilter_Base {
31 public:
SkImageImageFilter(sk_sp<SkImage> image,const SkRect & srcRect,const SkRect & dstRect,const SkSamplingOptions & sampling)32     SkImageImageFilter(sk_sp<SkImage> image,
33                        const SkRect& srcRect,
34                        const SkRect& dstRect,
35                        const SkSamplingOptions& sampling)
36             : SkImageFilter_Base(nullptr, 0)
37             , fImage(std::move(image))
38             , fSrcRect(srcRect)
39             , fDstRect(dstRect)
40             , fSampling(sampling) {
41         // The dst rect should be non-empty
42         SkASSERT(fImage && !dstRect.isEmpty());
43     }
44 
computeFastBounds(const SkRect &) const45     SkRect computeFastBounds(const SkRect&) const override { return SkRect(fDstRect); }
46 
47 protected:
48     void flatten(SkWriteBuffer&) const override;
49 
50 private:
51     friend void ::SkRegisterImageImageFilterFlattenable();
SK_FLATTENABLE_HOOKS(SkImageImageFilter)52     SK_FLATTENABLE_HOOKS(SkImageImageFilter)
53 
54     MatrixCapability onGetCTMCapability() const override { return MatrixCapability::kComplex; }
55 
56     skif::FilterResult onFilterImage(const skif::Context&) const override;
57 
58     skif::LayerSpace<SkIRect> onGetInputLayerBounds(
59             const skif::Mapping& mapping,
60             const skif::LayerSpace<SkIRect>& desiredOutput,
61             std::optional<skif::LayerSpace<SkIRect>> contentBounds) const override;
62 
63     std::optional<skif::LayerSpace<SkIRect>> onGetOutputLayerBounds(
64             const skif::Mapping& mapping,
65             std::optional<skif::LayerSpace<SkIRect>> contentBounds) const override;
66 
67     sk_sp<SkImage> fImage;
68     // The src rect is relative to the image's contents, so is not technically in the parameter
69     // coordinate space that responds to the layer matrix (unlike fDstRect).
70     SkRect fSrcRect;
71     skif::ParameterSpace<SkRect> fDstRect;
72     SkSamplingOptions fSampling;
73 };
74 
75 } // end namespace
76 
Image(sk_sp<SkImage> image,const SkRect & srcRect,const SkRect & dstRect,const SkSamplingOptions & sampling)77 sk_sp<SkImageFilter> SkImageFilters::Image(sk_sp<SkImage> image,
78                                            const SkRect& srcRect,
79                                            const SkRect& dstRect,
80                                            const SkSamplingOptions& sampling) {
81     if (srcRect.isEmpty() || dstRect.isEmpty() || !image) {
82         // There is no content to draw, so the filter should produce transparent black
83         return SkImageFilters::Empty();
84     } else {
85         SkRect imageBounds = SkRect::Make(image->dimensions());
86         if (imageBounds.contains(srcRect)) {
87             // No change to srcRect and dstRect needed
88             return sk_sp<SkImageFilter>(new SkImageImageFilter(
89                     std::move(image), srcRect, dstRect, sampling));
90         } else {
91             SkMatrix srcToDst = SkMatrix::RectToRect(srcRect, dstRect);
92             if (!imageBounds.intersect(srcRect)) {
93                 // No overlap, so draw empty
94                 return SkImageFilters::Empty();
95             }
96 
97             // Adjust dstRect to match the updated src (which is stored in imageBounds)
98             SkRect mappedBounds = srcToDst.mapRect(imageBounds);
99             if (mappedBounds.isEmpty()) {
100                 return SkImageFilters::Empty();
101             }
102             return sk_sp<SkImageFilter>(new SkImageImageFilter(
103                     std::move(image), imageBounds, mappedBounds, sampling));
104         }
105     }
106 }
107 
SkRegisterImageImageFilterFlattenable()108 void SkRegisterImageImageFilterFlattenable() {
109     SK_REGISTER_FLATTENABLE(SkImageImageFilter);
110     // TODO (michaelludwig) - Remove after grace period for SKPs to stop using old name
111     SkFlattenable::Register("SkImageSourceImpl", SkImageImageFilter::CreateProc);
112 }
113 
CreateProc(SkReadBuffer & buffer)114 sk_sp<SkFlattenable> SkImageImageFilter::CreateProc(SkReadBuffer& buffer) {
115     SkSamplingOptions sampling;
116     if (buffer.isVersionLT(SkPicturePriv::kImageFilterImageSampling_Version)) {
117         sampling = SkSamplingPriv::FromFQ(buffer.checkFilterQuality(), kLinear_SkMediumAs);
118     } else {
119         sampling = buffer.readSampling();
120     }
121 
122     SkRect src, dst;
123     buffer.readRect(&src);
124     buffer.readRect(&dst);
125 
126     sk_sp<SkImage> image(buffer.readImage());
127     if (!image) {
128         return nullptr;
129     }
130 
131     return SkImageFilters::Image(std::move(image), src, dst, sampling);
132 }
133 
flatten(SkWriteBuffer & buffer) const134 void SkImageImageFilter::flatten(SkWriteBuffer& buffer) const {
135     buffer.writeSampling(fSampling);
136     buffer.writeRect(fSrcRect);
137     buffer.writeRect(SkRect(fDstRect));
138     buffer.writeImage(fImage.get());
139 }
140 
141 ///////////////////////////////////////////////////////////////////////////////////////////////////
142 
onFilterImage(const skif::Context & ctx) const143 skif::FilterResult SkImageImageFilter::onFilterImage(const skif::Context& ctx) const {
144     return skif::FilterResult::MakeFromImage(ctx, fImage, fSrcRect, fDstRect, fSampling);
145 }
146 
onGetInputLayerBounds(const skif::Mapping &,const skif::LayerSpace<SkIRect> &,std::optional<skif::LayerSpace<SkIRect>>) const147 skif::LayerSpace<SkIRect> SkImageImageFilter::onGetInputLayerBounds(
148         const skif::Mapping&,
149         const skif::LayerSpace<SkIRect>&,
150         std::optional<skif::LayerSpace<SkIRect>>) const {
151     // This is a leaf filter, it requires no input and no further recursion
152     return skif::LayerSpace<SkIRect>::Empty();
153 }
154 
onGetOutputLayerBounds(const skif::Mapping & mapping,std::optional<skif::LayerSpace<SkIRect>>) const155 std::optional<skif::LayerSpace<SkIRect>> SkImageImageFilter::onGetOutputLayerBounds(
156         const skif::Mapping& mapping,
157         std::optional<skif::LayerSpace<SkIRect>>) const {
158     // The output is the transformed bounds of the image.
159     return mapping.paramToLayer(fDstRect).roundOut();
160 }
161