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