epoger@google.com | ec3ed6a | 2011-07-28 14:26:00 +0000 | [diff] [blame] | 1 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 2 | /* |
epoger@google.com | ec3ed6a | 2011-07-28 14:26:00 +0000 | [diff] [blame] | 3 | * Copyright 2006 The Android Open Source Project |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 4 | * |
epoger@google.com | ec3ed6a | 2011-07-28 14:26:00 +0000 | [diff] [blame] | 5 | * Use of this source code is governed by a BSD-style license that can be |
| 6 | * found in the LICENSE file. |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 7 | */ |
| 8 | |
epoger@google.com | ec3ed6a | 2011-07-28 14:26:00 +0000 | [diff] [blame] | 9 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 10 | #ifndef SkMaskFilter_DEFINED |
| 11 | #define SkMaskFilter_DEFINED |
| 12 | |
| 13 | #include "SkFlattenable.h" |
| 14 | #include "SkMask.h" |
junov@chromium.org | 2ac4ef5 | 2012-04-04 15:16:51 +0000 | [diff] [blame] | 15 | #include "SkPaint.h" |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 16 | |
senorblanco@chromium.org | fbcd415 | 2013-10-23 14:03:22 +0000 | [diff] [blame] | 17 | class GrContext; |
commit-bot@chromium.org | cf34bc0 | 2014-01-30 15:34:43 +0000 | [diff] [blame] | 18 | class GrPaint; |
robertphillips@google.com | 4914931 | 2013-07-03 15:34:35 +0000 | [diff] [blame] | 19 | class SkBitmap; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 20 | class SkBlitter; |
| 21 | class SkBounder; |
| 22 | class SkMatrix; |
| 23 | class SkPath; |
reed@google.com | 045e62d | 2011-10-24 12:19:46 +0000 | [diff] [blame] | 24 | class SkRasterClip; |
scroggo@google.com | a8e33a9 | 2013-11-08 18:02:53 +0000 | [diff] [blame] | 25 | class SkRRect; |
commit-bot@chromium.org | cf34bc0 | 2014-01-30 15:34:43 +0000 | [diff] [blame] | 26 | class SkStrokeRec; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 27 | |
| 28 | /** \class SkMaskFilter |
| 29 | |
| 30 | SkMaskFilter is the base class for object that perform transformations on |
| 31 | an alpha-channel mask before drawing it. A subclass of SkMaskFilter may be |
| 32 | installed into a SkPaint. Once there, each time a primitive is drawn, it |
| 33 | is first scan converted into a SkMask::kA8_Format mask, and handed to the |
| 34 | filter, calling its filterMask() method. If this returns true, then the |
| 35 | new mask is used to render into the device. |
| 36 | |
| 37 | Blur and emboss are implemented as subclasses of SkMaskFilter. |
| 38 | */ |
bungeman@google.com | 4200dfe | 2012-10-13 17:13:18 +0000 | [diff] [blame] | 39 | class SK_API SkMaskFilter : public SkFlattenable { |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 40 | public: |
robertphillips@google.com | 0456e0b | 2012-06-27 14:03:26 +0000 | [diff] [blame] | 41 | SK_DECLARE_INST_COUNT(SkMaskFilter) |
| 42 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 43 | /** Returns the format of the resulting mask that this subclass will return |
| 44 | when its filterMask() method is called. |
| 45 | */ |
reed@google.com | 30711b7 | 2012-12-18 19:18:39 +0000 | [diff] [blame] | 46 | virtual SkMask::Format getFormat() const = 0; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 47 | |
| 48 | /** Create a new mask by filter the src mask. |
| 49 | If src.fImage == null, then do not allocate or create the dst image |
| 50 | but do fill out the other fields in dstMask. |
| 51 | If you do allocate a dst image, use SkMask::AllocImage() |
| 52 | If this returns false, dst mask is ignored. |
| 53 | @param dst the result of the filter. If src.fImage == null, dst should not allocate its image |
| 54 | @param src the original image to be filtered. |
| 55 | @param matrix the CTM |
| 56 | @param margin if not null, return the buffer dx/dy need when calculating the effect. Used when |
| 57 | drawing a clipped object to know how much larger to allocate the src before |
| 58 | applying the filter. If returning false, ignore this parameter. |
| 59 | @return true if the dst mask was correctly created. |
| 60 | */ |
mike@reedtribe.org | 4135f28 | 2011-04-20 11:04:30 +0000 | [diff] [blame] | 61 | virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&, |
reed@google.com | 30711b7 | 2012-12-18 19:18:39 +0000 | [diff] [blame] | 62 | SkIPoint* margin) const; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 63 | |
robertphillips@google.com | 4914931 | 2013-07-03 15:34:35 +0000 | [diff] [blame] | 64 | #if SK_SUPPORT_GPU |
| 65 | /** |
commit-bot@chromium.org | 41bf930 | 2014-01-08 22:25:53 +0000 | [diff] [blame] | 66 | * Returns true if the filter can be expressed a single-pass GrEffect without requiring an |
| 67 | * explicit input mask. Per-pixel, the effect receives the incoming mask's coverage as |
| 68 | * the input color and outputs the filtered covereage value. This means that each pixel's |
| 69 | * filtered coverage must only depend on the unfiltered mask value for that pixel and not on |
| 70 | * surrounding values. |
robertphillips@google.com | 4914931 | 2013-07-03 15:34:35 +0000 | [diff] [blame] | 71 | * |
commit-bot@chromium.org | 41bf930 | 2014-01-08 22:25:53 +0000 | [diff] [blame] | 72 | * If effect is non-NULL, a new GrEffect instance is stored in it. The caller assumes ownership |
| 73 | * of the effect and must unref it. |
robertphillips@google.com | 4914931 | 2013-07-03 15:34:35 +0000 | [diff] [blame] | 74 | */ |
commit-bot@chromium.org | 41bf930 | 2014-01-08 22:25:53 +0000 | [diff] [blame] | 75 | virtual bool asNewEffect(GrEffectRef** effect, |
| 76 | GrTexture*, |
| 77 | const SkMatrix& ctm) const; |
reed@google.com | 2b75f42 | 2011-07-07 13:43:38 +0000 | [diff] [blame] | 78 | |
| 79 | /** |
commit-bot@chromium.org | 41bf930 | 2014-01-08 22:25:53 +0000 | [diff] [blame] | 80 | * If asNewEffect() fails the filter may be implemented on the GPU by a subclass overriding |
| 81 | * filterMaskGPU (declared below). That code path requires constructing a src mask as input. |
| 82 | * Since that is a potentially expensive operation, the subclass must also override this |
| 83 | * function to indicate whether filterTextureMaskGPU would succeeed if the mask were to be |
| 84 | * created. |
robertphillips@google.com | 4914931 | 2013-07-03 15:34:35 +0000 | [diff] [blame] | 85 | * |
commit-bot@chromium.org | 41bf930 | 2014-01-08 22:25:53 +0000 | [diff] [blame] | 86 | * 'maskRect' returns the device space portion of the mask that the filter needs. The mask |
| 87 | * passed into 'filterMaskGPU' should have the same extent as 'maskRect' but be translated |
| 88 | * to the upper-left corner of the mask (i.e., (maskRect.fLeft, maskRect.fTop) appears at |
| 89 | * (0, 0) in the mask). |
reed@google.com | 2b75f42 | 2011-07-07 13:43:38 +0000 | [diff] [blame] | 90 | */ |
skia.committer@gmail.com | 1842adf | 2013-07-04 07:01:07 +0000 | [diff] [blame] | 91 | virtual bool canFilterMaskGPU(const SkRect& devBounds, |
robertphillips@google.com | 4914931 | 2013-07-03 15:34:35 +0000 | [diff] [blame] | 92 | const SkIRect& clipBounds, |
| 93 | const SkMatrix& ctm, |
| 94 | SkRect* maskRect) const; |
| 95 | |
| 96 | /** |
commit-bot@chromium.org | cf34bc0 | 2014-01-30 15:34:43 +0000 | [diff] [blame] | 97 | * Try to directly render the mask filter into the target. Returns |
| 98 | * true if drawing was successful. |
| 99 | */ |
| 100 | virtual bool directFilterMaskGPU(GrContext* context, |
| 101 | GrPaint* grp, |
| 102 | const SkStrokeRec& strokeRec, |
| 103 | const SkPath& path) const; |
| 104 | |
| 105 | /** |
commit-bot@chromium.org | 41bf930 | 2014-01-08 22:25:53 +0000 | [diff] [blame] | 106 | * This function is used to implement filters that require an explicit src mask. It should only |
| 107 | * be called if canFilterMaskGPU returned true and the maskRect param should be the output from |
| 108 | * that call. canOverwriteSrc indicates whether the implementation may treat src as a scratch |
| 109 | * texture and overwrite its contents. When true it is also legal to return src as the result. |
| 110 | * Implementations are free to get the GrContext from the src texture in order to create |
| 111 | * additional textures and perform multiple passes. |
robertphillips@google.com | 4914931 | 2013-07-03 15:34:35 +0000 | [diff] [blame] | 112 | */ |
skia.committer@gmail.com | 1842adf | 2013-07-04 07:01:07 +0000 | [diff] [blame] | 113 | virtual bool filterMaskGPU(GrTexture* src, |
commit-bot@chromium.org | 41bf930 | 2014-01-08 22:25:53 +0000 | [diff] [blame] | 114 | const SkMatrix& ctm, |
skia.committer@gmail.com | 1842adf | 2013-07-04 07:01:07 +0000 | [diff] [blame] | 115 | const SkRect& maskRect, |
robertphillips@google.com | 4914931 | 2013-07-03 15:34:35 +0000 | [diff] [blame] | 116 | GrTexture** result, |
| 117 | bool canOverwriteSrc) const; |
| 118 | #endif |
reed@google.com | 2b75f42 | 2011-07-07 13:43:38 +0000 | [diff] [blame] | 119 | |
reed@google.com | 9efd9a0 | 2012-01-30 15:41:43 +0000 | [diff] [blame] | 120 | /** |
| 121 | * The fast bounds function is used to enable the paint to be culled early |
| 122 | * in the drawing pipeline. This function accepts the current bounds of the |
| 123 | * paint as its src param and the filter adjust those bounds using its |
| 124 | * current mask and returns the result using the dest param. Callers are |
| 125 | * allowed to provide the same struct for both src and dest so each |
| 126 | * implementation must accomodate that behavior. |
| 127 | * |
| 128 | * The default impl calls filterMask with the src mask having no image, |
| 129 | * but subclasses may override this if they can compute the rect faster. |
| 130 | */ |
reed@google.com | 30711b7 | 2012-12-18 19:18:39 +0000 | [diff] [blame] | 131 | virtual void computeFastBounds(const SkRect& src, SkRect* dest) const; |
reed@google.com | 9efd9a0 | 2012-01-30 15:41:43 +0000 | [diff] [blame] | 132 | |
robertphillips@google.com | 0bd80fa | 2013-03-18 17:53:38 +0000 | [diff] [blame] | 133 | SkDEVCODE(virtual void toString(SkString* str) const = 0;) |
commit-bot@chromium.org | c0b7e10 | 2013-10-23 17:06:21 +0000 | [diff] [blame] | 134 | SK_DEFINE_FLATTENABLE_TYPE(SkMaskFilter) |
robertphillips@google.com | 0bd80fa | 2013-03-18 17:53:38 +0000 | [diff] [blame] | 135 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 136 | protected: |
commit-bot@chromium.org | 7c9d0f3 | 2014-02-21 10:13:32 +0000 | [diff] [blame^] | 137 | SkMaskFilter() {} |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 138 | // empty for now, but lets get our subclass to remember to init us for the future |
commit-bot@chromium.org | 8b0e8ac | 2014-01-30 18:58:24 +0000 | [diff] [blame] | 139 | SkMaskFilter(SkReadBuffer& buffer) : INHERITED(buffer) {} |
reed@google.com | 045e62d | 2011-10-24 12:19:46 +0000 | [diff] [blame] | 140 | |
reed@google.com | d729b3e | 2012-11-09 14:30:48 +0000 | [diff] [blame] | 141 | enum FilterReturn { |
| 142 | kFalse_FilterReturn, |
| 143 | kTrue_FilterReturn, |
| 144 | kUnimplemented_FilterReturn |
| 145 | }; |
| 146 | |
reed@google.com | dab9b4f | 2012-11-19 16:45:14 +0000 | [diff] [blame] | 147 | struct NinePatch { |
| 148 | SkMask fMask; // fBounds must have [0,0] in its top-left |
| 149 | SkIRect fOuterRect; // width/height must be >= fMask.fBounds' |
| 150 | SkIPoint fCenter; // identifies center row/col for stretching |
| 151 | }; |
| 152 | |
reed@google.com | d729b3e | 2012-11-09 14:30:48 +0000 | [diff] [blame] | 153 | /** |
| 154 | * Override if your subclass can filter a rect, and return the answer as |
| 155 | * a ninepatch mask to be stretched over the returned outerRect. On success |
| 156 | * return kTrue_FilterReturn. On failure (e.g. out of memory) return |
| 157 | * kFalse_FilterReturn. If the normal filterMask() entry-point should be |
| 158 | * called (the default) return kUnimplemented_FilterReturn. |
| 159 | * |
| 160 | * By convention, the caller will take the center rol/col from the returned |
| 161 | * mask as the slice it can replicate horizontally and vertically as we |
| 162 | * stretch the mask to fit inside outerRect. It is an error for outerRect |
| 163 | * to be smaller than the mask's bounds. This would imply that the width |
| 164 | * and height of the mask should be odd. This is not required, just that |
| 165 | * the caller will call mask.fBounds.centerX() and centerY() to find the |
| 166 | * strips that will be replicated. |
| 167 | */ |
reed@google.com | dab9b4f | 2012-11-19 16:45:14 +0000 | [diff] [blame] | 168 | virtual FilterReturn filterRectsToNine(const SkRect[], int count, |
| 169 | const SkMatrix&, |
| 170 | const SkIRect& clipBounds, |
reed@google.com | 30711b7 | 2012-12-18 19:18:39 +0000 | [diff] [blame] | 171 | NinePatch*) const; |
scroggo@google.com | a8e33a9 | 2013-11-08 18:02:53 +0000 | [diff] [blame] | 172 | /** |
| 173 | * Similar to filterRectsToNine, except it performs the work on a round rect. |
| 174 | */ |
| 175 | virtual FilterReturn filterRRectToNine(const SkRRect&, const SkMatrix&, |
| 176 | const SkIRect& clipBounds, |
| 177 | NinePatch*) const; |
reed@google.com | d729b3e | 2012-11-09 14:30:48 +0000 | [diff] [blame] | 178 | |
reed@google.com | 045e62d | 2011-10-24 12:19:46 +0000 | [diff] [blame] | 179 | private: |
| 180 | friend class SkDraw; |
| 181 | |
| 182 | /** Helper method that, given a path in device space, will rasterize it into a kA8_Format mask |
| 183 | and then call filterMask(). If this returns true, the specified blitter will be called |
| 184 | to render that mask. Returns false if filterMask() returned false. |
| 185 | This method is not exported to java. |
| 186 | */ |
| 187 | bool filterPath(const SkPath& devPath, const SkMatrix& devMatrix, |
junov@chromium.org | 2ac4ef5 | 2012-04-04 15:16:51 +0000 | [diff] [blame] | 188 | const SkRasterClip&, SkBounder*, SkBlitter* blitter, |
reed@google.com | 30711b7 | 2012-12-18 19:18:39 +0000 | [diff] [blame] | 189 | SkPaint::Style style) const; |
djsollen@google.com | 5492424 | 2012-03-29 15:18:04 +0000 | [diff] [blame] | 190 | |
scroggo@google.com | a8e33a9 | 2013-11-08 18:02:53 +0000 | [diff] [blame] | 191 | /** Helper method that, given a roundRect in device space, will rasterize it into a kA8_Format |
| 192 | mask and then call filterMask(). If this returns true, the specified blitter will be called |
| 193 | to render that mask. Returns false if filterMask() returned false. |
| 194 | */ |
| 195 | bool filterRRect(const SkRRect& devRRect, const SkMatrix& devMatrix, |
| 196 | const SkRasterClip&, SkBounder*, SkBlitter* blitter, |
| 197 | SkPaint::Style style) const; |
| 198 | |
djsollen@google.com | 5492424 | 2012-03-29 15:18:04 +0000 | [diff] [blame] | 199 | typedef SkFlattenable INHERITED; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 200 | }; |
| 201 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 202 | #endif |