• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "SkDevice.h"
10 #include "SkCanvas.h"
11 #include "SkReadBuffer.h"
12 #include "SkSurfaceProps.h"
13 #include "SkWriteBuffer.h"
14 #include "SkValidationUtils.h"
15 
SkPictureImageFilter(const SkPicture * picture)16 SkPictureImageFilter::SkPictureImageFilter(const SkPicture* picture)
17     : INHERITED(0, 0, nullptr)
18     , fPicture(SkSafeRef(picture))
19     , fCropRect(picture ? picture->cullRect() : SkRect::MakeEmpty())
20     , fPictureResolution(kDeviceSpace_PictureResolution)
21     , fFilterQuality(kLow_SkFilterQuality) {
22 }
23 
SkPictureImageFilter(const SkPicture * picture,const SkRect & cropRect,PictureResolution pictureResolution,SkFilterQuality filterQuality)24 SkPictureImageFilter::SkPictureImageFilter(const SkPicture* picture, const SkRect& cropRect,
25                                            PictureResolution pictureResolution,
26                                            SkFilterQuality filterQuality)
27     : INHERITED(0, 0, nullptr)
28     , fPicture(SkSafeRef(picture))
29     , fCropRect(cropRect)
30     , fPictureResolution(pictureResolution)
31     , fFilterQuality(filterQuality) {
32 }
33 
~SkPictureImageFilter()34 SkPictureImageFilter::~SkPictureImageFilter() {
35     SkSafeUnref(fPicture);
36 }
37 
CreateProc(SkReadBuffer & buffer)38 SkFlattenable* SkPictureImageFilter::CreateProc(SkReadBuffer& buffer) {
39     SkAutoTUnref<SkPicture> picture;
40     SkRect cropRect;
41 
42     if (buffer.isCrossProcess() && SkPicture::PictureIOSecurityPrecautionsEnabled()) {
43         buffer.validate(!buffer.readBool());
44     } else {
45         if (buffer.readBool()) {
46             picture.reset(SkPicture::CreateFromBuffer(buffer));
47         }
48     }
49     buffer.readRect(&cropRect);
50     PictureResolution pictureResolution;
51     if (buffer.isVersionLT(SkReadBuffer::kPictureImageFilterResolution_Version)) {
52         pictureResolution = kDeviceSpace_PictureResolution;
53     } else {
54         pictureResolution = (PictureResolution)buffer.readInt();
55     }
56 
57     if (kLocalSpace_PictureResolution == pictureResolution) {
58         //filterLevel is only serialized if pictureResolution is LocalSpace
59         SkFilterQuality filterQuality;
60         if (buffer.isVersionLT(SkReadBuffer::kPictureImageFilterLevel_Version)) {
61             filterQuality = kLow_SkFilterQuality;
62         } else {
63             filterQuality = (SkFilterQuality)buffer.readInt();
64         }
65         return CreateForLocalSpace(picture, cropRect, filterQuality);
66     }
67     return Create(picture, cropRect);
68 }
69 
flatten(SkWriteBuffer & buffer) const70 void SkPictureImageFilter::flatten(SkWriteBuffer& buffer) const {
71     if (buffer.isCrossProcess() && SkPicture::PictureIOSecurityPrecautionsEnabled()) {
72         buffer.writeBool(false);
73     } else {
74         bool hasPicture = (fPicture != nullptr);
75         buffer.writeBool(hasPicture);
76         if (hasPicture) {
77             fPicture->flatten(buffer);
78         }
79     }
80     buffer.writeRect(fCropRect);
81     buffer.writeInt(fPictureResolution);
82     if (kLocalSpace_PictureResolution == fPictureResolution) {
83         buffer.writeInt(fFilterQuality);
84     }
85 }
86 
onFilterImageDeprecated(Proxy * proxy,const SkBitmap &,const Context & ctx,SkBitmap * result,SkIPoint * offset) const87 bool SkPictureImageFilter::onFilterImageDeprecated(Proxy* proxy, const SkBitmap&,
88                                                    const Context& ctx,
89                                                    SkBitmap* result, SkIPoint* offset) const {
90     if (!fPicture) {
91         offset->fX = offset->fY = 0;
92         return true;
93     }
94 
95     SkRect floatBounds;
96     ctx.ctm().mapRect(&floatBounds, fCropRect);
97     SkIRect bounds = floatBounds.roundOut();
98     if (!bounds.intersect(ctx.clipBounds())) {
99         return false;
100     }
101 
102     if (bounds.isEmpty()) {
103         offset->fX = offset->fY = 0;
104         return true;
105     }
106 
107     SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
108     if (nullptr == device.get()) {
109         return false;
110     }
111 
112     if (kDeviceSpace_PictureResolution == fPictureResolution ||
113         0 == (ctx.ctm().getType() & ~SkMatrix::kTranslate_Mask)) {
114         this->drawPictureAtDeviceResolution(device.get(), bounds, ctx);
115     } else {
116         this->drawPictureAtLocalResolution(proxy, device.get(), bounds, ctx);
117     }
118 
119     *result = device.get()->accessBitmap(false);
120     offset->fX = bounds.fLeft;
121     offset->fY = bounds.fTop;
122     return true;
123 }
124 
drawPictureAtDeviceResolution(SkBaseDevice * device,const SkIRect & deviceBounds,const Context & ctx) const125 void SkPictureImageFilter::drawPictureAtDeviceResolution(SkBaseDevice* device,
126                                                          const SkIRect& deviceBounds,
127                                                          const Context& ctx) const {
128     SkCanvas canvas(device);
129 
130     canvas.translate(-SkIntToScalar(deviceBounds.fLeft), -SkIntToScalar(deviceBounds.fTop));
131     canvas.concat(ctx.ctm());
132     canvas.drawPicture(fPicture);
133 }
134 
drawPictureAtLocalResolution(Proxy * proxy,SkBaseDevice * device,const SkIRect & deviceBounds,const Context & ctx) const135 void SkPictureImageFilter::drawPictureAtLocalResolution(Proxy* proxy, SkBaseDevice* device,
136                                                         const SkIRect& deviceBounds,
137                                                         const Context& ctx) const {
138     SkMatrix inverseCtm;
139     if (!ctx.ctm().invert(&inverseCtm)) {
140         return;
141     }
142 
143     SkRect localBounds = SkRect::Make(ctx.clipBounds());
144     inverseCtm.mapRect(&localBounds);
145     if (!localBounds.intersect(fCropRect)) {
146         return;
147     }
148     SkIRect localIBounds = localBounds.roundOut();
149     SkAutoTUnref<SkBaseDevice> localDevice(proxy->createDevice(localIBounds.width(), localIBounds.height()));
150 
151     SkCanvas localCanvas(localDevice);
152     localCanvas.translate(-SkIntToScalar(localIBounds.fLeft), -SkIntToScalar(localIBounds.fTop));
153     localCanvas.drawPicture(fPicture);
154 
155     SkCanvas canvas(device);
156 
157     canvas.translate(-SkIntToScalar(deviceBounds.fLeft), -SkIntToScalar(deviceBounds.fTop));
158     canvas.concat(ctx.ctm());
159     SkPaint paint;
160     paint.setFilterQuality(fFilterQuality);
161     canvas.drawBitmap(localDevice.get()->accessBitmap(false), SkIntToScalar(localIBounds.fLeft),
162                       SkIntToScalar(localIBounds.fTop), &paint);
163 }
164 
165 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const166 void SkPictureImageFilter::toString(SkString* str) const {
167     str->appendf("SkPictureImageFilter: (");
168     str->appendf("crop: (%f,%f,%f,%f) ",
169                  fCropRect.fLeft, fCropRect.fTop, fCropRect.fRight, fCropRect.fBottom);
170     if (fPicture) {
171         str->appendf("picture: (%f,%f,%f,%f)",
172                      fPicture->cullRect().fLeft, fPicture->cullRect().fTop,
173                      fPicture->cullRect().fRight, fPicture->cullRect().fBottom);
174     }
175     str->append(")");
176 }
177 #endif
178