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