1 /* 2 * Copyright 2010 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 GrClip_DEFINED 9 #define GrClip_DEFINED 10 11 #include "SkRect.h" 12 #include "SkRRect.h" 13 14 class GrAppliedClip; 15 class GrContext; 16 class GrDrawContext; 17 18 /** 19 * GrClip is an abstract base class for applying a clip. It constructs a clip mask if necessary, and 20 * fills out a GrAppliedClip instructing the caller on how to set up the draw state. 21 */ 22 class GrClip { 23 public: 24 virtual bool quickContains(const SkRect&) const = 0; quickContains(const SkRRect & rrect)25 virtual bool quickContains(const SkRRect& rrect) const { 26 return this->quickContains(rrect.getBounds()); 27 } 28 virtual void getConservativeBounds(int width, int height, SkIRect* devResult, 29 bool* isIntersectionOfRects = nullptr) const = 0; 30 virtual bool apply(GrContext*, GrDrawContext*, bool useHWAA, bool hasUserStencilSettings, 31 GrAppliedClip* out) const = 0; 32 ~GrClip()33 virtual ~GrClip() {} 34 35 /** 36 * This method quickly and conservatively determines whether the entire clip is equivalent to 37 * intersection with a rrect. This will only return true if the rrect does not fully contain 38 * the render target bounds. Moreover, the returned rrect need not be contained by the render 39 * target bounds. We assume all draws will be implicitly clipped by the render target bounds. 40 * 41 * @param rtBounds The bounds of the render target that the clip will be applied to. 42 * @param rrect If return is true rrect will contain the rrect equivalent to the clip within 43 * rtBounds. 44 * @param aa If return is true aa will indicate whether the rrect clip is antialiased. 45 * @return true if the clip is equivalent to a single rrect, false otherwise. 46 * 47 */ 48 virtual bool isRRect(const SkRect& rtBounds, SkRRect* rrect, bool* aa) const = 0; 49 50 /** 51 * This is the maximum distance that a draw may extend beyond a clip's boundary and still count 52 * count as "on the other side". We leave some slack because floating point rounding error is 53 * likely to blame. The rationale for 1e-3 is that in the coverage case (and barring unexpected 54 * rounding), as long as coverage stays within 0.5 * 1/256 of its intended value it shouldn't 55 * have any effect on the final pixel values. 56 */ 57 constexpr static SkScalar kBoundsTolerance = 1e-3f; 58 59 /** 60 * Returns true if the given query bounds count as entirely inside the clip. 61 * 62 * @param innerClipBounds device-space rect contained by the clip (SkRect or SkIRect). 63 * @param queryBounds device-space bounds of the query region. 64 */ IsInsideClip(const TRect & innerClipBounds,const SkRect & queryBounds)65 template<typename TRect> constexpr static bool IsInsideClip(const TRect& innerClipBounds, 66 const SkRect& queryBounds) { 67 return innerClipBounds.fRight - innerClipBounds.fLeft > kBoundsTolerance && 68 innerClipBounds.fBottom - innerClipBounds.fTop > kBoundsTolerance && 69 innerClipBounds.fLeft < queryBounds.fLeft + kBoundsTolerance && 70 innerClipBounds.fTop < queryBounds.fTop + kBoundsTolerance && 71 innerClipBounds.fRight > queryBounds.fRight - kBoundsTolerance && 72 innerClipBounds.fBottom > queryBounds.fBottom - kBoundsTolerance; 73 } 74 75 /** 76 * Returns true if the given query bounds count as entirely outside the clip. 77 * 78 * @param outerClipBounds device-space rect that contains the clip (SkRect or SkIRect). 79 * @param queryBounds device-space bounds of the query region. 80 */ IsOutsideClip(const TRect & outerClipBounds,const SkRect & queryBounds)81 template<typename TRect> constexpr static bool IsOutsideClip(const TRect& outerClipBounds, 82 const SkRect& queryBounds) { 83 return outerClipBounds.fRight - outerClipBounds.fLeft <= kBoundsTolerance || 84 outerClipBounds.fBottom - outerClipBounds.fTop <= kBoundsTolerance || 85 outerClipBounds.fLeft >= queryBounds.fRight - kBoundsTolerance || 86 outerClipBounds.fTop >= queryBounds.fBottom - kBoundsTolerance || 87 outerClipBounds.fRight <= queryBounds.fLeft + kBoundsTolerance || 88 outerClipBounds.fBottom <= queryBounds.fTop + kBoundsTolerance; 89 } 90 91 /** 92 * Returns the minimal integer rect that counts as containing a given set of bounds. 93 */ GetPixelIBounds(const SkRect & bounds)94 static SkIRect GetPixelIBounds(const SkRect& bounds) { 95 return SkIRect::MakeLTRB(SkScalarFloorToInt(bounds.fLeft + kBoundsTolerance), 96 SkScalarFloorToInt(bounds.fTop + kBoundsTolerance), 97 SkScalarCeilToInt(bounds.fRight - kBoundsTolerance), 98 SkScalarCeilToInt(bounds.fBottom - kBoundsTolerance)); 99 } 100 101 /** 102 * Returns the minimal pixel-aligned rect that counts as containing a given set of bounds. 103 */ GetPixelBounds(const SkRect & bounds)104 static SkRect GetPixelBounds(const SkRect& bounds) { 105 return SkRect::MakeLTRB(SkScalarFloorToScalar(bounds.fLeft + kBoundsTolerance), 106 SkScalarFloorToScalar(bounds.fTop + kBoundsTolerance), 107 SkScalarCeilToScalar(bounds.fRight - kBoundsTolerance), 108 SkScalarCeilToScalar(bounds.fBottom - kBoundsTolerance)); 109 } 110 111 /** 112 * Returns true if the given rect counts as aligned with pixel boundaries. 113 */ IsPixelAligned(const SkRect & rect)114 static bool IsPixelAligned(const SkRect& rect) { 115 return SkScalarAbs(SkScalarRoundToScalar(rect.fLeft) - rect.fLeft) <= kBoundsTolerance && 116 SkScalarAbs(SkScalarRoundToScalar(rect.fTop) - rect.fTop) <= kBoundsTolerance && 117 SkScalarAbs(SkScalarRoundToScalar(rect.fRight) - rect.fRight) <= kBoundsTolerance && 118 SkScalarAbs(SkScalarRoundToScalar(rect.fBottom) - rect.fBottom) <= kBoundsTolerance; 119 } 120 }; 121 122 /** 123 * Specialized implementation for no clip. 124 */ 125 class GrNoClip final : public GrClip { 126 private: quickContains(const SkRect &)127 bool quickContains(const SkRect&) const final { 128 return true; 129 } quickContains(const SkRRect &)130 bool quickContains(const SkRRect&) const final { 131 return true; 132 } getConservativeBounds(int width,int height,SkIRect * devResult,bool * isIntersectionOfRects)133 void getConservativeBounds(int width, int height, SkIRect* devResult, 134 bool* isIntersectionOfRects) const final { 135 devResult->setXYWH(0, 0, width, height); 136 if (isIntersectionOfRects) { 137 *isIntersectionOfRects = true; 138 } 139 } apply(GrContext *,GrDrawContext *,bool,bool,GrAppliedClip *)140 bool apply(GrContext*, GrDrawContext*, bool, bool, GrAppliedClip*) const final { 141 return true; 142 } isRRect(const SkRect &,SkRRect *,bool *)143 bool isRRect(const SkRect&, SkRRect*, bool*) const override { return false; } 144 }; 145 146 #endif 147