blob: 91f4dc9f29756fc4c9008da3af0a35464b7b9311 [file] [log] [blame]
senorblanco@chromium.org53333002013-12-12 23:28:52 +00001/*
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"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000011#include "SkReadBuffer.h"
fmalita2d97bc12014-11-20 10:44:58 -080012#include "SkSurfaceProps.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000013#include "SkWriteBuffer.h"
senorblanco@chromium.org53333002013-12-12 23:28:52 +000014#include "SkValidationUtils.h"
15
senorblanco24e06d52015-03-18 12:11:33 -070016SkPictureImageFilter::SkPictureImageFilter(const SkPicture* picture)
17 : INHERITED(0, 0, NULL)
robertphillipsa8d7f0b2014-08-29 08:03:56 -070018 , fPicture(SkSafeRef(picture))
Justin Novosad52340752014-12-02 14:50:56 -050019 , fCropRect(picture ? picture->cullRect() : SkRect::MakeEmpty())
junovf3c78cc2014-12-09 13:07:22 -080020 , fPictureResolution(kDeviceSpace_PictureResolution)
reed93a12152015-03-16 10:08:34 -070021 , fFilterQuality(kLow_SkFilterQuality) {
senorblanco@chromium.org53333002013-12-12 23:28:52 +000022}
23
senorblanco5e5f9482014-08-26 12:27:12 -070024SkPictureImageFilter::SkPictureImageFilter(const SkPicture* picture, const SkRect& cropRect,
senorblanco24e06d52015-03-18 12:11:33 -070025 PictureResolution pictureResolution,
reed93a12152015-03-16 10:08:34 -070026 SkFilterQuality filterQuality)
senorblanco24e06d52015-03-18 12:11:33 -070027 : INHERITED(0, 0, NULL)
robertphillipsa8d7f0b2014-08-29 08:03:56 -070028 , fPicture(SkSafeRef(picture))
Justin Novosad52340752014-12-02 14:50:56 -050029 , fCropRect(cropRect)
junovf3c78cc2014-12-09 13:07:22 -080030 , fPictureResolution(pictureResolution)
reed93a12152015-03-16 10:08:34 -070031 , fFilterQuality(filterQuality) {
senorblanco@chromium.org53333002013-12-12 23:28:52 +000032}
33
34SkPictureImageFilter::~SkPictureImageFilter() {
35 SkSafeUnref(fPicture);
36}
37
reed9fa60da2014-08-21 07:59:51 -070038SkFlattenable* SkPictureImageFilter::CreateProc(SkReadBuffer& buffer) {
39 SkAutoTUnref<SkPicture> picture;
40 SkRect cropRect;
41
hendrikw446ee672015-06-16 09:28:37 -070042 if (buffer.isCrossProcess() && SkPicture::PictureIOSecurityPrecautionsEnabled()) {
robertphillipsc4bd39c2015-01-06 09:17:02 -080043 buffer.validate(!buffer.readBool());
hendrikw446ee672015-06-16 09:28:37 -070044 } else {
reed9fa60da2014-08-21 07:59:51 -070045 if (buffer.readBool()) {
46 picture.reset(SkPicture::CreateFromBuffer(buffer));
47 }
reed9fa60da2014-08-21 07:59:51 -070048 }
49 buffer.readRect(&cropRect);
Justin Novosad52340752014-12-02 14:50:56 -050050 PictureResolution pictureResolution;
51 if (buffer.isVersionLT(SkReadBuffer::kPictureImageFilterResolution_Version)) {
52 pictureResolution = kDeviceSpace_PictureResolution;
53 } else {
54 pictureResolution = (PictureResolution)buffer.readInt();
junovf3c78cc2014-12-09 13:07:22 -080055 }
reed9fa60da2014-08-21 07:59:51 -070056
junovf3c78cc2014-12-09 13:07:22 -080057 if (kLocalSpace_PictureResolution == pictureResolution) {
58 //filterLevel is only serialized if pictureResolution is LocalSpace
reed93a12152015-03-16 10:08:34 -070059 SkFilterQuality filterQuality;
junovf3c78cc2014-12-09 13:07:22 -080060 if (buffer.isVersionLT(SkReadBuffer::kPictureImageFilterLevel_Version)) {
reed93a12152015-03-16 10:08:34 -070061 filterQuality = kLow_SkFilterQuality;
junovf3c78cc2014-12-09 13:07:22 -080062 } else {
reed93a12152015-03-16 10:08:34 -070063 filterQuality = (SkFilterQuality)buffer.readInt();
junovf3c78cc2014-12-09 13:07:22 -080064 }
reed93a12152015-03-16 10:08:34 -070065 return CreateForLocalSpace(picture, cropRect, filterQuality);
Justin Novosad52340752014-12-02 14:50:56 -050066 }
reed9fa60da2014-08-21 07:59:51 -070067 return Create(picture, cropRect);
68}
senorblanco@chromium.org53333002013-12-12 23:28:52 +000069
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000070void SkPictureImageFilter::flatten(SkWriteBuffer& buffer) const {
hendrikw446ee672015-06-16 09:28:37 -070071 if (buffer.isCrossProcess() && SkPicture::PictureIOSecurityPrecautionsEnabled()) {
robertphillipsc4bd39c2015-01-06 09:17:02 -080072 buffer.writeBool(false);
hendrikw446ee672015-06-16 09:28:37 -070073 } else {
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +000074 bool hasPicture = (fPicture != NULL);
75 buffer.writeBool(hasPicture);
76 if (hasPicture) {
77 fPicture->flatten(buffer);
78 }
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +000079 }
commit-bot@chromium.orgcac5fd52014-03-10 10:51:58 +000080 buffer.writeRect(fCropRect);
Justin Novosad52340752014-12-02 14:50:56 -050081 buffer.writeInt(fPictureResolution);
junovf3c78cc2014-12-09 13:07:22 -080082 if (kLocalSpace_PictureResolution == fPictureResolution) {
reed93a12152015-03-16 10:08:34 -070083 buffer.writeInt(fFilterQuality);
junovf3c78cc2014-12-09 13:07:22 -080084 }
senorblanco@chromium.org53333002013-12-12 23:28:52 +000085}
86
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +000087bool SkPictureImageFilter::onFilterImage(Proxy* proxy, const SkBitmap&, const Context& ctx,
88 SkBitmap* result, SkIPoint* offset) const {
senorblanco@chromium.org53333002013-12-12 23:28:52 +000089 if (!fPicture) {
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000090 offset->fX = offset->fY = 0;
senorblanco@chromium.org53333002013-12-12 23:28:52 +000091 return true;
92 }
93
94 SkRect floatBounds;
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +000095 ctx.ctm().mapRect(&floatBounds, fCropRect);
reedb07a94f2014-11-19 05:03:18 -080096 SkIRect bounds = floatBounds.roundOut();
senorblanco3d822c22014-07-30 14:49:31 -070097 if (!bounds.intersect(ctx.clipBounds())) {
98 return false;
99 }
senorblanco@chromium.org53333002013-12-12 23:28:52 +0000100
101 if (bounds.isEmpty()) {
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000102 offset->fX = offset->fY = 0;
senorblanco@chromium.org53333002013-12-12 23:28:52 +0000103 return true;
104 }
105
106 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
107 if (NULL == device.get()) {
108 return false;
109 }
110
junovf3c78cc2014-12-09 13:07:22 -0800111 if (kDeviceSpace_PictureResolution == fPictureResolution ||
112 0 == (ctx.ctm().getType() & ~SkMatrix::kTranslate_Mask)) {
113 drawPictureAtDeviceResolution(proxy, device.get(), bounds, ctx);
Justin Novosad52340752014-12-02 14:50:56 -0500114 } else {
junovf3c78cc2014-12-09 13:07:22 -0800115 drawPictureAtLocalResolution(proxy, device.get(), bounds, ctx);
Justin Novosad52340752014-12-02 14:50:56 -0500116 }
senorblanco@chromium.org53333002013-12-12 23:28:52 +0000117
118 *result = device.get()->accessBitmap(false);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000119 offset->fX = bounds.fLeft;
120 offset->fY = bounds.fTop;
senorblanco@chromium.org53333002013-12-12 23:28:52 +0000121 return true;
122}
Justin Novosad52340752014-12-02 14:50:56 -0500123
124void SkPictureImageFilter::drawPictureAtDeviceResolution(Proxy* proxy, SkBaseDevice* device,
125 const SkIRect& deviceBounds,
126 const Context& ctx) const {
127 // Pass explicit surface props, as the simplified canvas constructor discards device properties.
128 // FIXME: switch back to the public constructor (and unfriend) after
129 // https://code.google.com/p/skia/issues/detail?id=3142 is fixed.
reed2c55d7b2015-06-09 08:18:39 -0700130 SkCanvas canvas(device, &proxy->surfaceProps(), SkCanvas::kDefault_InitFlags);
Justin Novosad52340752014-12-02 14:50:56 -0500131
132 canvas.translate(-SkIntToScalar(deviceBounds.fLeft), -SkIntToScalar(deviceBounds.fTop));
133 canvas.concat(ctx.ctm());
134 canvas.drawPicture(fPicture);
135}
136
137void SkPictureImageFilter::drawPictureAtLocalResolution(Proxy* proxy, SkBaseDevice* device,
138 const SkIRect& deviceBounds,
139 const Context& ctx) const {
140 SkMatrix inverseCtm;
141 if (!ctx.ctm().invert(&inverseCtm))
142 return;
143 SkRect localBounds = SkRect::Make(ctx.clipBounds());
144 inverseCtm.mapRect(&localBounds);
145 if (!localBounds.intersect(fCropRect))
146 return;
147 SkIRect localIBounds = localBounds.roundOut();
148 SkAutoTUnref<SkBaseDevice> localDevice(proxy->createDevice(localIBounds.width(), localIBounds.height()));
149
150 // Pass explicit surface props, as the simplified canvas constructor discards device properties.
151 // FIXME: switch back to the public constructor (and unfriend) after
152 // https://code.google.com/p/skia/issues/detail?id=3142 is fixed.
reed2c55d7b2015-06-09 08:18:39 -0700153 SkCanvas localCanvas(localDevice, &proxy->surfaceProps(), SkCanvas::kDefault_InitFlags);
Justin Novosad52340752014-12-02 14:50:56 -0500154 localCanvas.translate(-SkIntToScalar(localIBounds.fLeft), -SkIntToScalar(localIBounds.fTop));
155 localCanvas.drawPicture(fPicture);
156
157 // Pass explicit surface props, as the simplified canvas constructor discards device properties.
158 // FIXME: switch back to the public constructor (and unfriend) after
159 // https://code.google.com/p/skia/issues/detail?id=3142 is fixed.
reed2c55d7b2015-06-09 08:18:39 -0700160 SkCanvas canvas(device, &proxy->surfaceProps(), SkCanvas::kDefault_InitFlags);
Justin Novosad52340752014-12-02 14:50:56 -0500161
162 canvas.translate(-SkIntToScalar(deviceBounds.fLeft), -SkIntToScalar(deviceBounds.fTop));
163 canvas.concat(ctx.ctm());
164 SkPaint paint;
reed93a12152015-03-16 10:08:34 -0700165 paint.setFilterQuality(fFilterQuality);
junovf3c78cc2014-12-09 13:07:22 -0800166 canvas.drawBitmap(localDevice.get()->accessBitmap(false), SkIntToScalar(localIBounds.fLeft),
167 SkIntToScalar(localIBounds.fTop), &paint);
Justin Novosad52340752014-12-02 14:50:56 -0500168 //canvas.drawPicture(fPicture);
169}
robertphillipsf3f5bad2014-12-19 13:49:15 -0800170
171#ifndef SK_IGNORE_TO_STRING
172void SkPictureImageFilter::toString(SkString* str) const {
173 str->appendf("SkPictureImageFilter: (");
174 str->appendf("crop: (%f,%f,%f,%f) ",
175 fCropRect.fLeft, fCropRect.fTop, fCropRect.fRight, fCropRect.fBottom);
176 if (fPicture) {
177 str->appendf("picture: (%f,%f,%f,%f)",
178 fPicture->cullRect().fLeft, fPicture->cullRect().fTop,
179 fPicture->cullRect().fRight, fPicture->cullRect().fBottom);
180 }
181 str->append(")");
182}
183#endif