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 SkRasterClip_DEFINED
9#define SkRasterClip_DEFINED
10
11#include "SkRegion.h"
12#include "SkAAClip.h"
13
14class SkRasterClip {
15public:
16    SkRasterClip(bool forceConservativeRects = false);
17    SkRasterClip(const SkIRect&, bool forceConservativeRects = false);
18    SkRasterClip(const SkRasterClip&);
19    ~SkRasterClip();
20
21    bool isForceConservativeRects() const { return fForceConservativeRects; }
22
23    bool isBW() const { return fIsBW; }
24    bool isAA() const { return !fIsBW; }
25    const SkRegion& bwRgn() const { SkASSERT(fIsBW); return fBW; }
26    const SkAAClip& aaRgn() const { SkASSERT(!fIsBW); return fAA; }
27
28    bool isEmpty() const {
29        SkASSERT(this->computeIsEmpty() == fIsEmpty);
30        return fIsEmpty;
31    }
32
33    bool isRect() const {
34        SkASSERT(this->computeIsRect() == fIsRect);
35        return fIsRect;
36    }
37
38    bool isComplex() const;
39    const SkIRect& getBounds() const;
40
41    bool setEmpty();
42    bool setRect(const SkIRect&);
43
44    bool op(const SkIRect&, SkRegion::Op);
45    bool op(const SkRegion&, SkRegion::Op);
46    bool op(const SkRect&, const SkISize&, SkRegion::Op, bool doAA);
47    bool op(const SkPath&, const SkISize&, SkRegion::Op, bool doAA);
48
49    void translate(int dx, int dy, SkRasterClip* dst) const;
50    void translate(int dx, int dy) {
51        this->translate(dx, dy, this);
52    }
53
54    bool quickContains(const SkIRect& rect) const;
55    bool quickContains(int left, int top, int right, int bottom) const {
56        return quickContains(SkIRect::MakeLTRB(left, top, right, bottom));
57    }
58
59    /**
60     *  Return true if this region is empty, or if the specified rectangle does
61     *  not intersect the region. Returning false is not a guarantee that they
62     *  intersect, but returning true is a guarantee that they do not.
63     */
64    bool quickReject(const SkIRect& rect) const {
65        return !SkIRect::Intersects(this->getBounds(), rect);
66    }
67
68    // hack for SkCanvas::getTotalClip
69    const SkRegion& forceGetBW();
70
71#ifdef SK_DEBUG
72    void validate() const;
73#else
74    void validate() const {}
75#endif
76
77private:
78    SkRegion    fBW;
79    SkAAClip    fAA;
80    bool        fForceConservativeRects;
81    bool        fIsBW;
82    // these 2 are caches based on querying the right obj based on fIsBW
83    bool        fIsEmpty;
84    bool        fIsRect;
85
86    bool computeIsEmpty() const {
87        return fIsBW ? fBW.isEmpty() : fAA.isEmpty();
88    }
89
90    bool computeIsRect() const {
91        return fIsBW ? fBW.isRect() : fAA.isRect();
92    }
93
94    bool updateCacheAndReturnNonEmpty(bool detectAARect = true) {
95        fIsEmpty = this->computeIsEmpty();
96
97        // detect that our computed AA is really just a (hard-edged) rect
98        if (detectAARect && !fIsEmpty && !fIsBW && fAA.isRect()) {
99            fBW.setRect(fAA.getBounds());
100            fAA.setEmpty(); // don't need this guy anymore
101            fIsBW = true;
102        }
103
104        fIsRect = this->computeIsRect();
105        return !fIsEmpty;
106    }
107
108    void convertToAA();
109
110    bool setPath(const SkPath& path, const SkRegion& clip, bool doAA);
111    bool setPath(const SkPath& path, const SkIRect& clip, bool doAA);
112    bool op(const SkRasterClip&, SkRegion::Op);
113    bool setConservativeRect(const SkRect& r, const SkIRect& clipR, bool isInverse);
114};
115
116class SkAutoRasterClipValidate : SkNoncopyable {
117public:
118    SkAutoRasterClipValidate(const SkRasterClip& rc) : fRC(rc) {
119        fRC.validate();
120    }
121    ~SkAutoRasterClipValidate() {
122        fRC.validate();
123    }
124private:
125    const SkRasterClip& fRC;
126};
127#define SkAutoRasterClipValidate(...) SK_REQUIRE_LOCAL_VAR(SkAutoRasterClipValidate)
128
129#ifdef SK_DEBUG
130    #define AUTO_RASTERCLIP_VALIDATE(rc)    SkAutoRasterClipValidate arcv(rc)
131#else
132    #define AUTO_RASTERCLIP_VALIDATE(rc)
133#endif
134
135///////////////////////////////////////////////////////////////////////////////
136
137/**
138 *  Encapsulates the logic of deciding if we need to change/wrap the blitter
139 *  for aaclipping. If so, getRgn and getBlitter return modified values. If
140 *  not, they return the raw blitter and (bw) clip region.
141 *
142 *  We need to keep the constructor/destructor cost as small as possible, so we
143 *  can freely put this guy on the stack, and not pay too much for the case when
144 *  we're really BW anyways.
145 */
146class SkAAClipBlitterWrapper {
147public:
148    SkAAClipBlitterWrapper();
149    SkAAClipBlitterWrapper(const SkRasterClip&, SkBlitter*);
150    SkAAClipBlitterWrapper(const SkAAClip*, SkBlitter*);
151
152    void init(const SkRasterClip&, SkBlitter*);
153
154    const SkIRect& getBounds() const {
155        SkASSERT(fClipRgn);
156        return fClipRgn->getBounds();
157    }
158    const SkRegion& getRgn() const {
159        SkASSERT(fClipRgn);
160        return *fClipRgn;
161    }
162    SkBlitter* getBlitter() {
163        SkASSERT(fBlitter);
164        return fBlitter;
165    }
166
167private:
168    SkRegion        fBWRgn;
169    SkAAClipBlitter fAABlitter;
170    // what we return
171    const SkRegion* fClipRgn;
172    SkBlitter* fBlitter;
173};
174
175#endif
176