Line data Source code
1 :
2 : /*
3 : * Copyright 2006 The Android Open Source Project
4 : *
5 : * Use of this source code is governed by a BSD-style license that can be
6 : * found in the LICENSE file.
7 : */
8 :
9 :
10 : #ifndef SkMaskFilter_DEFINED
11 : #define SkMaskFilter_DEFINED
12 :
13 : #include "SkBlurTypes.h"
14 : #include "SkFlattenable.h"
15 : #include "SkMask.h"
16 : #include "SkPaint.h"
17 : #include "SkStrokeRec.h"
18 :
19 : class GrClip;
20 : class GrContext;
21 : class GrRenderTargetContext;
22 : class GrPaint;
23 : class GrFragmentProcessor;
24 : class GrRenderTarget;
25 : class GrResourceProvider;
26 : class GrTexture;
27 : class GrTextureProxy;
28 : class SkBitmap;
29 : class SkBlitter;
30 : class SkCachedData;
31 : class SkMatrix;
32 : class SkPath;
33 : class SkRasterClip;
34 : class SkRRect;
35 :
36 : /** \class SkMaskFilter
37 :
38 : SkMaskFilter is the base class for object that perform transformations on
39 : an alpha-channel mask before drawing it. A subclass of SkMaskFilter may be
40 : installed into a SkPaint. Once there, each time a primitive is drawn, it
41 : is first scan converted into a SkMask::kA8_Format mask, and handed to the
42 : filter, calling its filterMask() method. If this returns true, then the
43 : new mask is used to render into the device.
44 :
45 : Blur and emboss are implemented as subclasses of SkMaskFilter.
46 : */
47 0 : class SK_API SkMaskFilter : public SkFlattenable {
48 : public:
49 : /** Returns the format of the resulting mask that this subclass will return
50 : when its filterMask() method is called.
51 : */
52 : virtual SkMask::Format getFormat() const = 0;
53 :
54 : /** Create a new mask by filter the src mask.
55 : If src.fImage == null, then do not allocate or create the dst image
56 : but do fill out the other fields in dstMask.
57 : If you do allocate a dst image, use SkMask::AllocImage()
58 : If this returns false, dst mask is ignored.
59 : @param dst the result of the filter. If src.fImage == null, dst should not allocate its image
60 : @param src the original image to be filtered.
61 : @param matrix the CTM
62 : @param margin if not null, return the buffer dx/dy need when calculating the effect. Used when
63 : drawing a clipped object to know how much larger to allocate the src before
64 : applying the filter. If returning false, ignore this parameter.
65 : @return true if the dst mask was correctly created.
66 : */
67 : virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&,
68 : SkIPoint* margin) const;
69 :
70 : #if SK_SUPPORT_GPU
71 : /**
72 : * Returns true if the filter can be expressed a single-pass GrProcessor without requiring an
73 : * explicit input mask. Per-pixel, the effect receives the incoming mask's coverage as
74 : * the input color and outputs the filtered covereage value. This means that each pixel's
75 : * filtered coverage must only depend on the unfiltered mask value for that pixel and not on
76 : * surrounding values.
77 : *
78 : * If effect is non-NULL, a new GrProcessor instance is stored in it. The caller assumes
79 : * ownership of the effect and must unref it.
80 : */
81 : virtual bool asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix& ctm) const;
82 :
83 : /**
84 : * If asFragmentProcessor() fails the filter may be implemented on the GPU by a subclass
85 : * overriding filterMaskGPU (declared below). That code path requires constructing a
86 : * src mask as input. Since that is a potentially expensive operation, the subclass must also
87 : * override this function to indicate whether filterTextureMaskGPU would succeeed if the mask
88 : * were to be created.
89 : *
90 : * 'maskRect' returns the device space portion of the mask that the filter needs. The mask
91 : * passed into 'filterMaskGPU' should have the same extent as 'maskRect' but be
92 : * translated to the upper-left corner of the mask (i.e., (maskRect.fLeft, maskRect.fTop)
93 : * appears at (0, 0) in the mask).
94 : *
95 : * Logically, how this works is:
96 : * canFilterMaskGPU is called
97 : * if (it returns true)
98 : * the returned mask rect is used for quick rejecting
99 : * either directFilterMaskGPU or directFilterRRectMaskGPU is then called
100 : * if (neither of them handle the blur)
101 : * the mask rect is used to generate the mask
102 : * filterMaskGPU is called to filter the mask
103 : *
104 : * TODO: this should work as:
105 : * if (canFilterMaskGPU(devShape, ...)) // rect, rrect, drrect, path
106 : * filterMaskGPU(devShape, ...)
107 : * this would hide the RRect special case and the mask generation
108 : */
109 : virtual bool canFilterMaskGPU(const SkRRect& devRRect,
110 : const SkIRect& clipBounds,
111 : const SkMatrix& ctm,
112 : SkRect* maskRect) const;
113 :
114 : /**
115 : * Try to directly render the mask filter into the target. Returns true if drawing was
116 : * successful. If false is returned then paint is unmodified.
117 : */
118 : virtual bool directFilterMaskGPU(GrContext*,
119 : GrRenderTargetContext* renderTargetContext,
120 : GrPaint&& paint,
121 : const GrClip&,
122 : const SkMatrix& viewMatrix,
123 : const SkStrokeRec& strokeRec,
124 : const SkPath& path) const;
125 : /**
126 : * Try to directly render a rounded rect mask filter into the target. Returns
127 : * true if drawing was successful. If false is returned then paint is unmodified.
128 : */
129 : virtual bool directFilterRRectMaskGPU(GrContext*,
130 : GrRenderTargetContext* renderTargetContext,
131 : GrPaint&& paint,
132 : const GrClip&,
133 : const SkMatrix& viewMatrix,
134 : const SkStrokeRec& strokeRec,
135 : const SkRRect& rrect,
136 : const SkRRect& devRRect) const;
137 :
138 : /**
139 : * This function is used to implement filters that require an explicit src mask. It should only
140 : * be called if canFilterMaskGPU returned true and the maskRect param should be the output from
141 : * that call.
142 : * Implementations are free to get the GrContext from the src texture in order to create
143 : * additional textures and perform multiple passes.
144 : */
145 : virtual sk_sp<GrTextureProxy> filterMaskGPU(GrContext*,
146 : sk_sp<GrTextureProxy> srcProxy,
147 : const SkMatrix& ctm,
148 : const SkIRect& maskRect) const;
149 : #endif
150 :
151 : /**
152 : * The fast bounds function is used to enable the paint to be culled early
153 : * in the drawing pipeline. This function accepts the current bounds of the
154 : * paint as its src param and the filter adjust those bounds using its
155 : * current mask and returns the result using the dest param. Callers are
156 : * allowed to provide the same struct for both src and dest so each
157 : * implementation must accomodate that behavior.
158 : *
159 : * The default impl calls filterMask with the src mask having no image,
160 : * but subclasses may override this if they can compute the rect faster.
161 : */
162 : virtual void computeFastBounds(const SkRect& src, SkRect* dest) const;
163 :
164 : struct BlurRec {
165 : SkScalar fSigma;
166 : SkBlurStyle fStyle;
167 : SkBlurQuality fQuality;
168 : };
169 : /**
170 : * If this filter can be represented by a BlurRec, return true and (if not null) fill in the
171 : * provided BlurRec parameter. If this effect cannot be represented as a BlurRec, return false
172 : * and ignore the BlurRec parameter.
173 : */
174 : virtual bool asABlur(BlurRec*) const;
175 :
176 : SK_TO_STRING_PUREVIRT()
177 0 : SK_DEFINE_FLATTENABLE_TYPE(SkMaskFilter)
178 :
179 : protected:
180 0 : SkMaskFilter() {}
181 :
182 : enum FilterReturn {
183 : kFalse_FilterReturn,
184 : kTrue_FilterReturn,
185 : kUnimplemented_FilterReturn
186 : };
187 :
188 : class NinePatch : ::SkNoncopyable {
189 : public:
190 0 : NinePatch() : fCache(nullptr) { }
191 : ~NinePatch();
192 :
193 : SkMask fMask; // fBounds must have [0,0] in its top-left
194 : SkIRect fOuterRect; // width/height must be >= fMask.fBounds'
195 : SkIPoint fCenter; // identifies center row/col for stretching
196 : SkCachedData* fCache;
197 : };
198 :
199 : /**
200 : * Override if your subclass can filter a rect, and return the answer as
201 : * a ninepatch mask to be stretched over the returned outerRect. On success
202 : * return kTrue_FilterReturn. On failure (e.g. out of memory) return
203 : * kFalse_FilterReturn. If the normal filterMask() entry-point should be
204 : * called (the default) return kUnimplemented_FilterReturn.
205 : *
206 : * By convention, the caller will take the center rol/col from the returned
207 : * mask as the slice it can replicate horizontally and vertically as we
208 : * stretch the mask to fit inside outerRect. It is an error for outerRect
209 : * to be smaller than the mask's bounds. This would imply that the width
210 : * and height of the mask should be odd. This is not required, just that
211 : * the caller will call mask.fBounds.centerX() and centerY() to find the
212 : * strips that will be replicated.
213 : */
214 : virtual FilterReturn filterRectsToNine(const SkRect[], int count,
215 : const SkMatrix&,
216 : const SkIRect& clipBounds,
217 : NinePatch*) const;
218 : /**
219 : * Similar to filterRectsToNine, except it performs the work on a round rect.
220 : */
221 : virtual FilterReturn filterRRectToNine(const SkRRect&, const SkMatrix&,
222 : const SkIRect& clipBounds,
223 : NinePatch*) const;
224 :
225 : private:
226 : friend class SkDraw;
227 :
228 : /** Helper method that, given a path in device space, will rasterize it into a kA8_Format mask
229 : and then call filterMask(). If this returns true, the specified blitter will be called
230 : to render that mask. Returns false if filterMask() returned false.
231 : This method is not exported to java.
232 : */
233 : bool filterPath(const SkPath& devPath, const SkMatrix& ctm, const SkRasterClip&, SkBlitter*,
234 : SkStrokeRec::InitStyle) const;
235 :
236 : /** Helper method that, given a roundRect in device space, will rasterize it into a kA8_Format
237 : mask and then call filterMask(). If this returns true, the specified blitter will be called
238 : to render that mask. Returns false if filterMask() returned false.
239 : */
240 : bool filterRRect(const SkRRect& devRRect, const SkMatrix& ctm, const SkRasterClip&,
241 : SkBlitter*) const;
242 :
243 : typedef SkFlattenable INHERITED;
244 : };
245 :
246 : #endif
|