blob: e18600db6e24275b78b09fa4e4155c99cd02bc82 [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
senorblanco5e5f9482014-08-26 12:27:12 -070016SkPictureImageFilter::SkPictureImageFilter(const SkPicture* picture, uint32_t uniqueID)
robertphillipsa8d7f0b2014-08-29 08:03:56 -070017 : INHERITED(0, 0, NULL, uniqueID)
18 , fPicture(SkSafeRef(picture))
Justin Novosad52340752014-12-02 14:50:56 -050019 , fCropRect(picture ? picture->cullRect() : SkRect::MakeEmpty())
20 , fPictureResolution(kDeviceSpace_PictureResolution) {
senorblanco@chromium.org53333002013-12-12 23:28:52 +000021}
22
senorblanco5e5f9482014-08-26 12:27:12 -070023SkPictureImageFilter::SkPictureImageFilter(const SkPicture* picture, const SkRect& cropRect,
Justin Novosad52340752014-12-02 14:50:56 -050024 uint32_t uniqueID, PictureResolution pictureResolution)
robertphillipsa8d7f0b2014-08-29 08:03:56 -070025 : INHERITED(0, 0, NULL, uniqueID)
26 , fPicture(SkSafeRef(picture))
Justin Novosad52340752014-12-02 14:50:56 -050027 , fCropRect(cropRect)
28 , fPictureResolution(pictureResolution) {
senorblanco@chromium.org53333002013-12-12 23:28:52 +000029}
30
31SkPictureImageFilter::~SkPictureImageFilter() {
32 SkSafeUnref(fPicture);
33}
34
reed9fa60da2014-08-21 07:59:51 -070035SkFlattenable* SkPictureImageFilter::CreateProc(SkReadBuffer& buffer) {
36 SkAutoTUnref<SkPicture> picture;
37 SkRect cropRect;
38
39 if (!buffer.isCrossProcess()) {
40 if (buffer.readBool()) {
41 picture.reset(SkPicture::CreateFromBuffer(buffer));
42 }
43 } else {
44 buffer.validate(!buffer.readBool());
45 }
46 buffer.readRect(&cropRect);
Justin Novosad52340752014-12-02 14:50:56 -050047 PictureResolution pictureResolution;
48 if (buffer.isVersionLT(SkReadBuffer::kPictureImageFilterResolution_Version)) {
49 pictureResolution = kDeviceSpace_PictureResolution;
50 } else {
51 pictureResolution = (PictureResolution)buffer.readInt();
52 }
reed9fa60da2014-08-21 07:59:51 -070053
Justin Novosad52340752014-12-02 14:50:56 -050054 if (pictureResolution == kLocalSpace_PictureResolution) {
55 return CreateForLocalSpace(picture, cropRect);
56 }
reed9fa60da2014-08-21 07:59:51 -070057 return Create(picture, cropRect);
58}
senorblanco@chromium.org53333002013-12-12 23:28:52 +000059
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000060void SkPictureImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +000061 if (!buffer.isCrossProcess()) {
62 bool hasPicture = (fPicture != NULL);
63 buffer.writeBool(hasPicture);
64 if (hasPicture) {
65 fPicture->flatten(buffer);
66 }
67 } else {
68 buffer.writeBool(false);
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +000069 }
commit-bot@chromium.orgcac5fd52014-03-10 10:51:58 +000070 buffer.writeRect(fCropRect);
Justin Novosad52340752014-12-02 14:50:56 -050071 buffer.writeInt(fPictureResolution);
senorblanco@chromium.org53333002013-12-12 23:28:52 +000072}
73
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +000074bool SkPictureImageFilter::onFilterImage(Proxy* proxy, const SkBitmap&, const Context& ctx,
75 SkBitmap* result, SkIPoint* offset) const {
senorblanco@chromium.org53333002013-12-12 23:28:52 +000076 if (!fPicture) {
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000077 offset->fX = offset->fY = 0;
senorblanco@chromium.org53333002013-12-12 23:28:52 +000078 return true;
79 }
80
81 SkRect floatBounds;
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +000082 ctx.ctm().mapRect(&floatBounds, fCropRect);
reedb07a94f2014-11-19 05:03:18 -080083 SkIRect bounds = floatBounds.roundOut();
senorblanco3d822c22014-07-30 14:49:31 -070084 if (!bounds.intersect(ctx.clipBounds())) {
85 return false;
86 }
senorblanco@chromium.org53333002013-12-12 23:28:52 +000087
88 if (bounds.isEmpty()) {
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000089 offset->fX = offset->fY = 0;
senorblanco@chromium.org53333002013-12-12 23:28:52 +000090 return true;
91 }
92
93 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
94 if (NULL == device.get()) {
95 return false;
96 }
97
Justin Novosad52340752014-12-02 14:50:56 -050098 if (kLocalSpace_PictureResolution == fPictureResolution &&
99 (ctx.ctm().getType() & ~SkMatrix::kTranslate_Mask)) {
100 drawPictureAtLocalResolution(proxy, device.get(), bounds, ctx);
101 } else {
102 drawPictureAtDeviceResolution(proxy, device.get(), bounds, ctx);
103 }
senorblanco@chromium.org53333002013-12-12 23:28:52 +0000104
105 *result = device.get()->accessBitmap(false);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000106 offset->fX = bounds.fLeft;
107 offset->fY = bounds.fTop;
senorblanco@chromium.org53333002013-12-12 23:28:52 +0000108 return true;
109}
Justin Novosad52340752014-12-02 14:50:56 -0500110
111void SkPictureImageFilter::drawPictureAtDeviceResolution(Proxy* proxy, SkBaseDevice* device,
112 const SkIRect& deviceBounds,
113 const Context& ctx) const {
114 // Pass explicit surface props, as the simplified canvas constructor discards device properties.
115 // FIXME: switch back to the public constructor (and unfriend) after
116 // https://code.google.com/p/skia/issues/detail?id=3142 is fixed.
117 SkCanvas canvas(device, proxy->surfaceProps(), SkCanvas::kDefault_InitFlags);
118
119 canvas.translate(-SkIntToScalar(deviceBounds.fLeft), -SkIntToScalar(deviceBounds.fTop));
120 canvas.concat(ctx.ctm());
121 canvas.drawPicture(fPicture);
122}
123
124void SkPictureImageFilter::drawPictureAtLocalResolution(Proxy* proxy, SkBaseDevice* device,
125 const SkIRect& deviceBounds,
126 const Context& ctx) const {
127 SkMatrix inverseCtm;
128 if (!ctx.ctm().invert(&inverseCtm))
129 return;
130 SkRect localBounds = SkRect::Make(ctx.clipBounds());
131 inverseCtm.mapRect(&localBounds);
132 if (!localBounds.intersect(fCropRect))
133 return;
134 SkIRect localIBounds = localBounds.roundOut();
135 SkAutoTUnref<SkBaseDevice> localDevice(proxy->createDevice(localIBounds.width(), localIBounds.height()));
136
137 // Pass explicit surface props, as the simplified canvas constructor discards device properties.
138 // FIXME: switch back to the public constructor (and unfriend) after
139 // https://code.google.com/p/skia/issues/detail?id=3142 is fixed.
140 SkCanvas localCanvas(localDevice, proxy->surfaceProps(), SkCanvas::kDefault_InitFlags);
141 localCanvas.translate(-SkIntToScalar(localIBounds.fLeft), -SkIntToScalar(localIBounds.fTop));
142 localCanvas.drawPicture(fPicture);
143
144 // Pass explicit surface props, as the simplified canvas constructor discards device properties.
145 // FIXME: switch back to the public constructor (and unfriend) after
146 // https://code.google.com/p/skia/issues/detail?id=3142 is fixed.
147 SkCanvas canvas(device, proxy->surfaceProps(), SkCanvas::kDefault_InitFlags);
148
149 canvas.translate(-SkIntToScalar(deviceBounds.fLeft), -SkIntToScalar(deviceBounds.fTop));
150 canvas.concat(ctx.ctm());
151 SkPaint paint;
152 paint.setFilterLevel(SkPaint::kLow_FilterLevel);
153 canvas.drawBitmap(localDevice.get()->accessBitmap(false), SkIntToScalar(localIBounds.fLeft), SkIntToScalar(localIBounds.fTop), &paint);
154 //canvas.drawPicture(fPicture);
155}