1533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org/*
2533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org * Copyright 2013 The Android Open Source Project
3533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org *
4533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org * Use of this source code is governed by a BSD-style license that can be
5533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org * found in the LICENSE file.
6533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org */
7533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org
8533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org#include "SkPictureImageFilter.h"
9533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org#include "SkDevice.h"
10533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org#include "SkCanvas.h"
118b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkReadBuffer.h"
122d97bc139a7de5813468bd3dbfd0037351ae5606fmalita#include "SkSurfaceProps.h"
138b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkWriteBuffer.h"
14533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org#include "SkValidationUtils.h"
15533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org
1624e06d5244ae96e440410e1d76e039983b2efac9senorblancoSkPictureImageFilter::SkPictureImageFilter(const SkPicture* picture)
1724e06d5244ae96e440410e1d76e039983b2efac9senorblanco    : INHERITED(0, 0, NULL)
18a8d7f0b13cd4c6d773fcf055fe17db75d260fa05robertphillips    , fPicture(SkSafeRef(picture))
195234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    , fCropRect(picture ? picture->cullRect() : SkRect::MakeEmpty())
20f3c78ccf5694d22d2e4a7061a80399a7e69b59dbjunov    , fPictureResolution(kDeviceSpace_PictureResolution)
2193a1215fe0ab007ce941c721f1fd3e9dcb5d4754reed    , fFilterQuality(kLow_SkFilterQuality) {
22533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org}
23533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org
245e5f948b6b363dbfc8c076d8ff0c6b8e9ea99958senorblancoSkPictureImageFilter::SkPictureImageFilter(const SkPicture* picture, const SkRect& cropRect,
2524e06d5244ae96e440410e1d76e039983b2efac9senorblanco                                           PictureResolution pictureResolution,
2693a1215fe0ab007ce941c721f1fd3e9dcb5d4754reed                                           SkFilterQuality filterQuality)
2724e06d5244ae96e440410e1d76e039983b2efac9senorblanco    : INHERITED(0, 0, NULL)
28a8d7f0b13cd4c6d773fcf055fe17db75d260fa05robertphillips    , fPicture(SkSafeRef(picture))
295234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    , fCropRect(cropRect)
30f3c78ccf5694d22d2e4a7061a80399a7e69b59dbjunov    , fPictureResolution(pictureResolution)
3193a1215fe0ab007ce941c721f1fd3e9dcb5d4754reed    , fFilterQuality(filterQuality) {
32533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org}
33533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org
34533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.orgSkPictureImageFilter::~SkPictureImageFilter() {
35533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org    SkSafeUnref(fPicture);
36533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org}
37533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org
389fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reedSkFlattenable* SkPictureImageFilter::CreateProc(SkReadBuffer& buffer) {
399fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    SkAutoTUnref<SkPicture> picture;
409fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    SkRect cropRect;
419fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed
42c4bd39c903cc5da16f50d711063b01723b59281crobertphillips#ifdef SK_DISALLOW_CROSSPROCESS_PICTUREIMAGEFILTERS
43c4bd39c903cc5da16f50d711063b01723b59281crobertphillips    if (buffer.isCrossProcess()) {
44c4bd39c903cc5da16f50d711063b01723b59281crobertphillips        buffer.validate(!buffer.readBool());
45c4bd39c903cc5da16f50d711063b01723b59281crobertphillips    } else
46c4bd39c903cc5da16f50d711063b01723b59281crobertphillips#endif
47c4bd39c903cc5da16f50d711063b01723b59281crobertphillips    {
489fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed        if (buffer.readBool()) {
499fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed            picture.reset(SkPicture::CreateFromBuffer(buffer));
509fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed        }
519fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    }
529fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    buffer.readRect(&cropRect);
535234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    PictureResolution pictureResolution;
545234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    if (buffer.isVersionLT(SkReadBuffer::kPictureImageFilterResolution_Version)) {
555234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad        pictureResolution = kDeviceSpace_PictureResolution;
565234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    } else {
575234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad        pictureResolution = (PictureResolution)buffer.readInt();
58f3c78ccf5694d22d2e4a7061a80399a7e69b59dbjunov    }
59f3c78ccf5694d22d2e4a7061a80399a7e69b59dbjunov
60f3c78ccf5694d22d2e4a7061a80399a7e69b59dbjunov    if (kLocalSpace_PictureResolution == pictureResolution) {
61f3c78ccf5694d22d2e4a7061a80399a7e69b59dbjunov        //filterLevel is only serialized if pictureResolution is LocalSpace
6293a1215fe0ab007ce941c721f1fd3e9dcb5d4754reed        SkFilterQuality filterQuality;
63f3c78ccf5694d22d2e4a7061a80399a7e69b59dbjunov        if (buffer.isVersionLT(SkReadBuffer::kPictureImageFilterLevel_Version)) {
6493a1215fe0ab007ce941c721f1fd3e9dcb5d4754reed            filterQuality = kLow_SkFilterQuality;
65f3c78ccf5694d22d2e4a7061a80399a7e69b59dbjunov        } else {
6693a1215fe0ab007ce941c721f1fd3e9dcb5d4754reed            filterQuality = (SkFilterQuality)buffer.readInt();
67f3c78ccf5694d22d2e4a7061a80399a7e69b59dbjunov        }
6893a1215fe0ab007ce941c721f1fd3e9dcb5d4754reed        return CreateForLocalSpace(picture, cropRect, filterQuality);
695234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    }
709fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    return Create(picture, cropRect);
719fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed}
72533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org
738b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.orgvoid SkPictureImageFilter::flatten(SkWriteBuffer& buffer) const {
74c4bd39c903cc5da16f50d711063b01723b59281crobertphillips#ifdef SK_DISALLOW_CROSSPROCESS_PICTUREIMAGEFILTERS
75c4bd39c903cc5da16f50d711063b01723b59281crobertphillips    if (buffer.isCrossProcess()) {
76c4bd39c903cc5da16f50d711063b01723b59281crobertphillips        buffer.writeBool(false);
77c4bd39c903cc5da16f50d711063b01723b59281crobertphillips    } else
78c4bd39c903cc5da16f50d711063b01723b59281crobertphillips#endif
79c4bd39c903cc5da16f50d711063b01723b59281crobertphillips    {
8097f5fc651956287e78e35934cf62b9e1b45b4f6csenorblanco@chromium.org        bool hasPicture = (fPicture != NULL);
8197f5fc651956287e78e35934cf62b9e1b45b4f6csenorblanco@chromium.org        buffer.writeBool(hasPicture);
8297f5fc651956287e78e35934cf62b9e1b45b4f6csenorblanco@chromium.org        if (hasPicture) {
8397f5fc651956287e78e35934cf62b9e1b45b4f6csenorblanco@chromium.org            fPicture->flatten(buffer);
8497f5fc651956287e78e35934cf62b9e1b45b4f6csenorblanco@chromium.org        }
855e0995e4b36178e1e4465a9f50114ed39f038c27commit-bot@chromium.org    }
86cac5fd597f6e2495f50aaa6bcbe3dadc56f0b977commit-bot@chromium.org    buffer.writeRect(fCropRect);
875234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    buffer.writeInt(fPictureResolution);
88f3c78ccf5694d22d2e4a7061a80399a7e69b59dbjunov    if (kLocalSpace_PictureResolution == fPictureResolution) {
8993a1215fe0ab007ce941c721f1fd3e9dcb5d4754reed        buffer.writeInt(fFilterQuality);
90f3c78ccf5694d22d2e4a7061a80399a7e69b59dbjunov    }
91533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org}
92533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org
934cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.orgbool SkPictureImageFilter::onFilterImage(Proxy* proxy, const SkBitmap&, const Context& ctx,
944cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org                                         SkBitmap* result, SkIPoint* offset) const {
95533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org    if (!fPicture) {
966776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org        offset->fX = offset->fY = 0;
97533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org        return true;
98533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org    }
99533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org
100533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org    SkRect floatBounds;
1014cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org    ctx.ctm().mapRect(&floatBounds, fCropRect);
102b07a94f1cba3976596ae1a7f23d8c2043ba353f3reed    SkIRect bounds = floatBounds.roundOut();
1033d822c29d4272a6749e59801b202b1ed6d611be8senorblanco    if (!bounds.intersect(ctx.clipBounds())) {
1043d822c29d4272a6749e59801b202b1ed6d611be8senorblanco        return false;
1053d822c29d4272a6749e59801b202b1ed6d611be8senorblanco    }
106533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org
107533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org    if (bounds.isEmpty()) {
1086776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org        offset->fX = offset->fY = 0;
109533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org        return true;
110533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org    }
111533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org
112533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org    SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
113533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org    if (NULL == device.get()) {
114533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org        return false;
115533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org    }
116533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org
117f3c78ccf5694d22d2e4a7061a80399a7e69b59dbjunov    if (kDeviceSpace_PictureResolution == fPictureResolution ||
118f3c78ccf5694d22d2e4a7061a80399a7e69b59dbjunov        0 == (ctx.ctm().getType() & ~SkMatrix::kTranslate_Mask)) {
119f3c78ccf5694d22d2e4a7061a80399a7e69b59dbjunov        drawPictureAtDeviceResolution(proxy, device.get(), bounds, ctx);
1205234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    } else {
121f3c78ccf5694d22d2e4a7061a80399a7e69b59dbjunov        drawPictureAtLocalResolution(proxy, device.get(), bounds, ctx);
1225234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    }
1235234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad
1245234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    *result = device.get()->accessBitmap(false);
1255234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    offset->fX = bounds.fLeft;
1265234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    offset->fY = bounds.fTop;
1275234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    return true;
1285234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad}
1295234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad
1305234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosadvoid SkPictureImageFilter::drawPictureAtDeviceResolution(Proxy* proxy, SkBaseDevice* device,
1315234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad                                                         const SkIRect& deviceBounds,
1325234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad                                                         const Context& ctx) const {
1332d97bc139a7de5813468bd3dbfd0037351ae5606fmalita    // Pass explicit surface props, as the simplified canvas constructor discards device properties.
1342d97bc139a7de5813468bd3dbfd0037351ae5606fmalita    // FIXME: switch back to the public constructor (and unfriend) after
1352d97bc139a7de5813468bd3dbfd0037351ae5606fmalita    //        https://code.google.com/p/skia/issues/detail?id=3142 is fixed.
1365234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    SkCanvas canvas(device, proxy->surfaceProps(), SkCanvas::kDefault_InitFlags);
137533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org
1385234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    canvas.translate(-SkIntToScalar(deviceBounds.fLeft), -SkIntToScalar(deviceBounds.fTop));
1394cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org    canvas.concat(ctx.ctm());
1409b14f26d0f3a974f3dd626c8354e1db1cfcd322frobertphillips    canvas.drawPicture(fPicture);
1415234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad}
142533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org
1435234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosadvoid SkPictureImageFilter::drawPictureAtLocalResolution(Proxy* proxy, SkBaseDevice* device,
1445234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad                                                        const SkIRect& deviceBounds,
1455234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad                                                        const Context& ctx) const {
1465234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    SkMatrix inverseCtm;
1475234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    if (!ctx.ctm().invert(&inverseCtm))
1485234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad        return;
1495234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    SkRect localBounds = SkRect::Make(ctx.clipBounds());
1505234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    inverseCtm.mapRect(&localBounds);
1515234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    if (!localBounds.intersect(fCropRect))
1525234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad        return;
1535234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    SkIRect localIBounds = localBounds.roundOut();
1545234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    SkAutoTUnref<SkBaseDevice> localDevice(proxy->createDevice(localIBounds.width(), localIBounds.height()));
1555234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad
1565234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    // Pass explicit surface props, as the simplified canvas constructor discards device properties.
1575234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    // FIXME: switch back to the public constructor (and unfriend) after
1585234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    //        https://code.google.com/p/skia/issues/detail?id=3142 is fixed.
1595234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    SkCanvas localCanvas(localDevice, proxy->surfaceProps(), SkCanvas::kDefault_InitFlags);
1605234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    localCanvas.translate(-SkIntToScalar(localIBounds.fLeft), -SkIntToScalar(localIBounds.fTop));
1615234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    localCanvas.drawPicture(fPicture);
1625234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad
1635234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    // Pass explicit surface props, as the simplified canvas constructor discards device properties.
1645234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    // FIXME: switch back to the public constructor (and unfriend) after
1655234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    //        https://code.google.com/p/skia/issues/detail?id=3142 is fixed.
1665234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    SkCanvas canvas(device, proxy->surfaceProps(), SkCanvas::kDefault_InitFlags);
1675234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad
1685234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    canvas.translate(-SkIntToScalar(deviceBounds.fLeft), -SkIntToScalar(deviceBounds.fTop));
1695234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    canvas.concat(ctx.ctm());
1705234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    SkPaint paint;
17193a1215fe0ab007ce941c721f1fd3e9dcb5d4754reed    paint.setFilterQuality(fFilterQuality);
172f3c78ccf5694d22d2e4a7061a80399a7e69b59dbjunov    canvas.drawBitmap(localDevice.get()->accessBitmap(false), SkIntToScalar(localIBounds.fLeft),
173f3c78ccf5694d22d2e4a7061a80399a7e69b59dbjunov                      SkIntToScalar(localIBounds.fTop), &paint);
1745234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    //canvas.drawPicture(fPicture);
175533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org}
176f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips
177f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips#ifndef SK_IGNORE_TO_STRING
178f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillipsvoid SkPictureImageFilter::toString(SkString* str) const {
179f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips    str->appendf("SkPictureImageFilter: (");
180f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips    str->appendf("crop: (%f,%f,%f,%f) ",
181f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips                 fCropRect.fLeft, fCropRect.fTop, fCropRect.fRight, fCropRect.fBottom);
182f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips    if (fPicture) {
183f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips        str->appendf("picture: (%f,%f,%f,%f)",
184f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips                     fPicture->cullRect().fLeft, fPicture->cullRect().fTop,
185f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips                     fPicture->cullRect().fRight, fPicture->cullRect().fBottom);
186f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips    }
187f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips    str->append(")");
188f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips}
189f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips#endif
190