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