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