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 "include/effects/SkPictureImageFilter.h" |
9 | |
10 | #include "include/core/SkCanvas.h" |
11 | #include "include/core/SkPicture.h" |
12 | #include "include/effects/SkImageSource.h" |
13 | #include "src/core/SkImageFilter_Base.h" |
14 | #include "src/core/SkPicturePriv.h" |
15 | #include "src/core/SkReadBuffer.h" |
16 | #include "src/core/SkSpecialImage.h" |
17 | #include "src/core/SkSpecialSurface.h" |
18 | #include "src/core/SkValidationUtils.h" |
19 | #include "src/core/SkWriteBuffer.h" |
20 | |
21 | namespace { |
22 | |
23 | class SkPictureImageFilterImpl final : public SkImageFilter_Base { |
24 | public: |
25 | SkPictureImageFilterImpl(sk_sp<SkPicture> picture, const SkRect& cropRect) |
26 | : INHERITED(nullptr, 0, nullptr) |
27 | , fPicture(std::move(picture)) |
28 | , fCropRect(cropRect) {} |
29 | |
30 | protected: |
31 | /* Constructs an SkPictureImageFilter object from an SkReadBuffer. |
32 | * Note: If the SkPictureImageFilter object construction requires bitmap |
33 | * decoding, the decoder must be set on the SkReadBuffer parameter by calling |
34 | * SkReadBuffer::setBitmapDecoder() before calling this constructor. |
35 | * @param SkReadBuffer Serialized picture data. |
36 | */ |
37 | void flatten(SkWriteBuffer&) const override; |
38 | sk_sp<SkSpecialImage> onFilterImage(const Context&, SkIPoint* offset) const override; |
39 | |
40 | private: |
41 | friend void SkPictureImageFilter::RegisterFlattenables(); |
42 | SK_FLATTENABLE_HOOKS(SkPictureImageFilterImpl) |
43 | |
44 | sk_sp<SkPicture> fPicture; |
45 | SkRect fCropRect; |
46 | |
47 | typedef SkImageFilter_Base INHERITED; |
48 | }; |
49 | |
50 | } // end namespace |
51 | |
52 | sk_sp<SkImageFilter> SkPictureImageFilter::Make(sk_sp<SkPicture> picture) { |
53 | SkRect cropRect = picture ? picture->cullRect() : SkRect::MakeEmpty(); |
54 | return Make(std::move(picture), cropRect); |
55 | } |
56 | |
57 | sk_sp<SkImageFilter> SkPictureImageFilter::Make(sk_sp<SkPicture> picture, const SkRect& cropRect) { |
58 | return sk_sp<SkImageFilter>(new SkPictureImageFilterImpl(std::move(picture), cropRect)); |
59 | } |
60 | |
61 | void SkPictureImageFilter::RegisterFlattenables() { |
62 | SK_REGISTER_FLATTENABLE(SkPictureImageFilterImpl); |
63 | // TODO (michaelludwig) - Remove after grace period for SKPs to stop using old name |
64 | SkFlattenable::Register("SkPictureImageFilter" , SkPictureImageFilterImpl::CreateProc); |
65 | } |
66 | |
67 | /////////////////////////////////////////////////////////////////////////////////////////////////// |
68 | |
69 | enum PictureResolution { |
70 | kDeviceSpace_PictureResolution, |
71 | kLocalSpace_PictureResolution |
72 | }; |
73 | static sk_sp<SkImageFilter> make_localspace_filter(sk_sp<SkPicture> pic, const SkRect& cropRect, |
74 | SkFilterQuality fq) { |
75 | SkISize dim = { SkScalarRoundToInt(cropRect.width()), SkScalarRoundToInt(cropRect.height()) }; |
76 | auto img = SkImage::MakeFromPicture(std::move(pic), dim, nullptr, nullptr, |
77 | SkImage::BitDepth::kU8, SkColorSpace::MakeSRGB()); |
78 | return SkImageSource::Make(img, cropRect, cropRect, fq); |
79 | } |
80 | |
81 | sk_sp<SkFlattenable> SkPictureImageFilterImpl::CreateProc(SkReadBuffer& buffer) { |
82 | sk_sp<SkPicture> picture; |
83 | SkRect cropRect; |
84 | |
85 | if (buffer.readBool()) { |
86 | picture = SkPicturePriv::MakeFromBuffer(buffer); |
87 | } |
88 | buffer.readRect(&cropRect); |
89 | |
90 | if (buffer.isVersionLT(SkPicturePriv::kRemovePictureImageFilterLocalSpace)) { |
91 | PictureResolution pictureResolution = buffer.checkRange<PictureResolution>( |
92 | kDeviceSpace_PictureResolution, kLocalSpace_PictureResolution); |
93 | if (kLocalSpace_PictureResolution == pictureResolution) { |
94 | return make_localspace_filter(std::move(picture), cropRect, |
95 | buffer.checkFilterQuality()); |
96 | } |
97 | } |
98 | return SkPictureImageFilter::Make(std::move(picture), cropRect); |
99 | } |
100 | |
101 | void SkPictureImageFilterImpl::flatten(SkWriteBuffer& buffer) const { |
102 | bool hasPicture = (fPicture != nullptr); |
103 | buffer.writeBool(hasPicture); |
104 | if (hasPicture) { |
105 | SkPicturePriv::Flatten(fPicture, buffer); |
106 | } |
107 | buffer.writeRect(fCropRect); |
108 | } |
109 | |
110 | sk_sp<SkSpecialImage> SkPictureImageFilterImpl::onFilterImage(const Context& ctx, |
111 | SkIPoint* offset) const { |
112 | if (!fPicture) { |
113 | return nullptr; |
114 | } |
115 | |
116 | SkRect floatBounds; |
117 | ctx.ctm().mapRect(&floatBounds, fCropRect); |
118 | SkIRect bounds = floatBounds.roundOut(); |
119 | if (!bounds.intersect(ctx.clipBounds())) { |
120 | return nullptr; |
121 | } |
122 | |
123 | SkASSERT(!bounds.isEmpty()); |
124 | |
125 | // Given the standard usage of the picture image filter (i.e., to render content at a fixed |
126 | // resolution that, most likely, differs from the screen's) disable LCD text. |
127 | SkSurfaceProps props(0, kUnknown_SkPixelGeometry); |
128 | sk_sp<SkSpecialSurface> surf(ctx.makeSurface(bounds.size(), &props)); |
129 | if (!surf) { |
130 | return nullptr; |
131 | } |
132 | |
133 | SkASSERT(kUnknown_SkPixelGeometry == surf->props().pixelGeometry()); |
134 | |
135 | SkCanvas* canvas = surf->getCanvas(); |
136 | SkASSERT(canvas); |
137 | canvas->clear(0x0); |
138 | |
139 | canvas->translate(-SkIntToScalar(bounds.fLeft), -SkIntToScalar(bounds.fTop)); |
140 | canvas->concat(ctx.ctm()); |
141 | canvas->drawPicture(fPicture); |
142 | |
143 | offset->fX = bounds.fLeft; |
144 | offset->fY = bounds.fTop; |
145 | return surf->makeImageSnapshot(); |
146 | } |
147 | |