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"
9fef28606d2c51be627be3a656581882e31945c03robertphillips
10533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org#include "SkCanvas.h"
11e22a6a29e2e5664ee907f1abccf615a900cbcfadMatt Sarett#include "SkColorSpaceXformCanvas.h"
12e22a6a29e2e5664ee907f1abccf615a900cbcfadMatt Sarett#include "SkColorSpaceXformer.h"
1348723156c597ec4d7be8e0648548ff27ef6c4e02Mike Reed#include "SkImageSource.h"
148b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkReadBuffer.h"
15fef28606d2c51be627be3a656581882e31945c03robertphillips#include "SkSpecialImage.h"
16fef28606d2c51be627be3a656581882e31945c03robertphillips#include "SkSpecialSurface.h"
178b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkWriteBuffer.h"
18533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org#include "SkValidationUtils.h"
19533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org
20225db4441e0cb887d52c906e8bb39df506304b3erobertphillipssk_sp<SkImageFilter> SkPictureImageFilter::Make(sk_sp<SkPicture> picture) {
21225db4441e0cb887d52c906e8bb39df506304b3erobertphillips    return sk_sp<SkImageFilter>(new SkPictureImageFilter(std::move(picture)));
22225db4441e0cb887d52c906e8bb39df506304b3erobertphillips}
23225db4441e0cb887d52c906e8bb39df506304b3erobertphillips
24225db4441e0cb887d52c906e8bb39df506304b3erobertphillipssk_sp<SkImageFilter> SkPictureImageFilter::Make(sk_sp<SkPicture> picture,
25225db4441e0cb887d52c906e8bb39df506304b3erobertphillips                                                const SkRect& cropRect) {
2648723156c597ec4d7be8e0648548ff27ef6c4e02Mike Reed    return sk_sp<SkImageFilter>(new SkPictureImageFilter(std::move(picture), cropRect, nullptr));
27225db4441e0cb887d52c906e8bb39df506304b3erobertphillips}
28225db4441e0cb887d52c906e8bb39df506304b3erobertphillips
295ff17b13524eea03e4b672ee3b3a49b649dd09fbrobertphillipsSkPictureImageFilter::SkPictureImageFilter(sk_sp<SkPicture> picture)
30372177ee115d46dfb5bfb881a408e6c37ae83678robertphillips    : INHERITED(nullptr, 0, nullptr)
315ff17b13524eea03e4b672ee3b3a49b649dd09fbrobertphillips    , fPicture(std::move(picture))
3248723156c597ec4d7be8e0648548ff27ef6c4e02Mike Reed    , fCropRect(fPicture ? fPicture->cullRect() : SkRect::MakeEmpty()) {
33533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org}
34533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org
355ff17b13524eea03e4b672ee3b3a49b649dd09fbrobertphillipsSkPictureImageFilter::SkPictureImageFilter(sk_sp<SkPicture> picture, const SkRect& cropRect,
36e22a6a29e2e5664ee907f1abccf615a900cbcfadMatt Sarett                                           sk_sp<SkColorSpace> colorSpace)
37372177ee115d46dfb5bfb881a408e6c37ae83678robertphillips    : INHERITED(nullptr, 0, nullptr)
385ff17b13524eea03e4b672ee3b3a49b649dd09fbrobertphillips    , fPicture(std::move(picture))
395234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    , fCropRect(cropRect)
40e22a6a29e2e5664ee907f1abccf615a900cbcfadMatt Sarett    , fColorSpace(std::move(colorSpace)) {
41533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org}
42533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org
4348723156c597ec4d7be8e0648548ff27ef6c4e02Mike Reedenum PictureResolution {
4448723156c597ec4d7be8e0648548ff27ef6c4e02Mike Reed    kDeviceSpace_PictureResolution,
4548723156c597ec4d7be8e0648548ff27ef6c4e02Mike Reed    kLocalSpace_PictureResolution
4648723156c597ec4d7be8e0648548ff27ef6c4e02Mike Reed};
4748723156c597ec4d7be8e0648548ff27ef6c4e02Mike Reedstatic sk_sp<SkImageFilter> make_localspace_filter(sk_sp<SkPicture> pic, const SkRect& cropRect,
4848723156c597ec4d7be8e0648548ff27ef6c4e02Mike Reed                                                   SkFilterQuality fq) {
4948723156c597ec4d7be8e0648548ff27ef6c4e02Mike Reed    SkISize dim = { SkScalarRoundToInt(cropRect.width()), SkScalarRoundToInt(cropRect.height()) };
5048723156c597ec4d7be8e0648548ff27ef6c4e02Mike Reed    auto img = SkImage::MakeFromPicture(std::move(pic), dim, nullptr, nullptr,
5148723156c597ec4d7be8e0648548ff27ef6c4e02Mike Reed                                        SkImage::BitDepth::kU8, SkColorSpace::MakeSRGB());
5248723156c597ec4d7be8e0648548ff27ef6c4e02Mike Reed    return SkImageSource::Make(img, cropRect, cropRect, fq);
5348723156c597ec4d7be8e0648548ff27ef6c4e02Mike Reed}
5448723156c597ec4d7be8e0648548ff27ef6c4e02Mike Reed
5560c9b58b3214b0154c931656e91e39b230e987d8reedsk_sp<SkFlattenable> SkPictureImageFilter::CreateProc(SkReadBuffer& buffer) {
56ca2622ba051829fed5f30facd74c5b41cd4b931creed    sk_sp<SkPicture> picture;
579fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    SkRect cropRect;
589fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed
595a0f3455320f5591c196844ff8a89b71a7d9aa56Mike Reed    if (buffer.readBool()) {
605a0f3455320f5591c196844ff8a89b71a7d9aa56Mike Reed        picture = SkPicture::MakeFromBuffer(buffer);
619fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    }
629fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    buffer.readRect(&cropRect);
63f3c78ccf5694d22d2e4a7061a80399a7e69b59dbjunov
6477e487dfc005be66346ebf3e33d3ec394de4cc36Mike Reed    if (buffer.isVersionLT(SkReadBuffer::kRemovePictureImageFilterLocalSpace)) {
6548723156c597ec4d7be8e0648548ff27ef6c4e02Mike Reed        PictureResolution pictureResolution = buffer.checkRange<PictureResolution>(
6648723156c597ec4d7be8e0648548ff27ef6c4e02Mike Reed            kDeviceSpace_PictureResolution, kLocalSpace_PictureResolution);
6777e487dfc005be66346ebf3e33d3ec394de4cc36Mike Reed        if (kLocalSpace_PictureResolution == pictureResolution) {
6848723156c597ec4d7be8e0648548ff27ef6c4e02Mike Reed            return make_localspace_filter(std::move(picture), cropRect,
6948723156c597ec4d7be8e0648548ff27ef6c4e02Mike Reed                                          buffer.checkFilterQuality());
7077e487dfc005be66346ebf3e33d3ec394de4cc36Mike Reed        }
715234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    }
7248723156c597ec4d7be8e0648548ff27ef6c4e02Mike Reed    return sk_sp<SkImageFilter>(new SkPictureImageFilter(picture, cropRect, nullptr));
739fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed}
74533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org
758b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.orgvoid SkPictureImageFilter::flatten(SkWriteBuffer& buffer) const {
765a0f3455320f5591c196844ff8a89b71a7d9aa56Mike Reed    bool hasPicture = (fPicture != nullptr);
775a0f3455320f5591c196844ff8a89b71a7d9aa56Mike Reed    buffer.writeBool(hasPicture);
785a0f3455320f5591c196844ff8a89b71a7d9aa56Mike Reed    if (hasPicture) {
795a0f3455320f5591c196844ff8a89b71a7d9aa56Mike Reed        fPicture->flatten(buffer);
805e0995e4b36178e1e4465a9f50114ed39f038c27commit-bot@chromium.org    }
81cac5fd597f6e2495f50aaa6bcbe3dadc56f0b977commit-bot@chromium.org    buffer.writeRect(fCropRect);
82533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org}
83533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org
84fef28606d2c51be627be3a656581882e31945c03robertphillipssk_sp<SkSpecialImage> SkPictureImageFilter::onFilterImage(SkSpecialImage* source,
85fef28606d2c51be627be3a656581882e31945c03robertphillips                                                          const Context& ctx,
86fef28606d2c51be627be3a656581882e31945c03robertphillips                                                          SkIPoint* offset) const {
87533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org    if (!fPicture) {
88fef28606d2c51be627be3a656581882e31945c03robertphillips        return nullptr;
89533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org    }
90533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org
91533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org    SkRect floatBounds;
924cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org    ctx.ctm().mapRect(&floatBounds, fCropRect);
93b07a94f1cba3976596ae1a7f23d8c2043ba353f3reed    SkIRect bounds = floatBounds.roundOut();
943d822c29d4272a6749e59801b202b1ed6d611be8senorblanco    if (!bounds.intersect(ctx.clipBounds())) {
95fef28606d2c51be627be3a656581882e31945c03robertphillips        return nullptr;
963d822c29d4272a6749e59801b202b1ed6d611be8senorblanco    }
97533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org
98fef28606d2c51be627be3a656581882e31945c03robertphillips    SkASSERT(!bounds.isEmpty());
99533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org
100eed6b0e1d865a1f93143c09961debba0aca592cabrianosman    sk_sp<SkSpecialSurface> surf(source->makeSurface(ctx.outputProperties(), bounds.size()));
101fef28606d2c51be627be3a656581882e31945c03robertphillips    if (!surf) {
102fef28606d2c51be627be3a656581882e31945c03robertphillips        return nullptr;
103533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org    }
104533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org
105fef28606d2c51be627be3a656581882e31945c03robertphillips    SkCanvas* canvas = surf->getCanvas();
106fef28606d2c51be627be3a656581882e31945c03robertphillips    SkASSERT(canvas);
107fef28606d2c51be627be3a656581882e31945c03robertphillips    canvas->clear(0x0);
108fef28606d2c51be627be3a656581882e31945c03robertphillips
10948723156c597ec4d7be8e0648548ff27ef6c4e02Mike Reed    std::unique_ptr<SkCanvas> xformCanvas;
11048723156c597ec4d7be8e0648548ff27ef6c4e02Mike Reed    if (fColorSpace) {
11148723156c597ec4d7be8e0648548ff27ef6c4e02Mike Reed        // Only non-null in the case where onMakeColorSpace() was called.  This instructs
11248723156c597ec4d7be8e0648548ff27ef6c4e02Mike Reed        // us to do the color space xform on playback.
11348723156c597ec4d7be8e0648548ff27ef6c4e02Mike Reed        xformCanvas = SkCreateColorSpaceXformCanvas(canvas, fColorSpace);
11448723156c597ec4d7be8e0648548ff27ef6c4e02Mike Reed        canvas = xformCanvas.get();
1155234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    }
11648723156c597ec4d7be8e0648548ff27ef6c4e02Mike Reed    canvas->translate(-SkIntToScalar(bounds.fLeft), -SkIntToScalar(bounds.fTop));
11748723156c597ec4d7be8e0648548ff27ef6c4e02Mike Reed    canvas->concat(ctx.ctm());
11848723156c597ec4d7be8e0648548ff27ef6c4e02Mike Reed    canvas->drawPicture(fPicture);
1195234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad
1205234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    offset->fX = bounds.fLeft;
1215234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad    offset->fY = bounds.fTop;
122fef28606d2c51be627be3a656581882e31945c03robertphillips    return surf->makeImageSnapshot();
1235234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad}
1245234075b1c6bcada4ad17ed5a83bfcb53df66b7fJustin Novosad
125e22a6a29e2e5664ee907f1abccf615a900cbcfadMatt Sarettsk_sp<SkImageFilter> SkPictureImageFilter::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
126a252c661d686393207b133cccbc6211620bf7772Florin Malita    sk_sp<SkColorSpace> dstCS = xformer->dst();
127604f0d54a8b22e6d1ec7581fcb68191aa0ff03fcFlorin Malita    if (SkColorSpace::Equals(dstCS.get(), fColorSpace.get())) {
128a252c661d686393207b133cccbc6211620bf7772Florin Malita        return this->refMe();
129a252c661d686393207b133cccbc6211620bf7772Florin Malita    }
130a252c661d686393207b133cccbc6211620bf7772Florin Malita
13148723156c597ec4d7be8e0648548ff27ef6c4e02Mike Reed    return sk_sp<SkImageFilter>(new SkPictureImageFilter(fPicture, fCropRect, std::move(dstCS)));
132533330065a28b51808e5bf564ae45e56f8d9956asenorblanco@chromium.org}
133f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips
134f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips#ifndef SK_IGNORE_TO_STRING
135f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillipsvoid SkPictureImageFilter::toString(SkString* str) const {
136f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips    str->appendf("SkPictureImageFilter: (");
1379d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary    str->appendf("crop: (%f,%f,%f,%f) ",
138f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips                 fCropRect.fLeft, fCropRect.fTop, fCropRect.fRight, fCropRect.fBottom);
139f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips    if (fPicture) {
140f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips        str->appendf("picture: (%f,%f,%f,%f)",
141f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips                     fPicture->cullRect().fLeft, fPicture->cullRect().fTop,
142f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips                     fPicture->cullRect().fRight, fPicture->cullRect().fBottom);
143f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips    }
144f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips    str->append(")");
145f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips}
146f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips#endif
147