1 :
2 : /*
3 : * Copyright 2005 The Android Open Source Project
4 : *
5 : * Use of this source code is governed by a BSD-style license that can be
6 : * found in the LICENSE file.
7 : */
8 :
9 :
10 : #ifndef SkRegion_DEFINED
11 : #define SkRegion_DEFINED
12 :
13 : #include "SkRect.h"
14 :
15 : class SkPath;
16 : class SkRgnBuilder;
17 :
18 : namespace android {
19 : class Region;
20 : }
21 :
22 : #define SkRegion_gEmptyRunHeadPtr ((SkRegion::RunHead*)-1)
23 : #define SkRegion_gRectRunHeadPtr 0
24 :
25 : /** \class SkRegion
26 :
27 : The SkRegion class encapsulates the geometric region used to specify
28 : clipping areas for drawing.
29 : */
30 : class SK_API SkRegion {
31 : public:
32 : typedef int32_t RunType;
33 : enum {
34 : kRunTypeSentinel = 0x7FFFFFFF
35 : };
36 :
37 : SkRegion();
38 : SkRegion(const SkRegion&);
39 : explicit SkRegion(const SkIRect&);
40 : ~SkRegion();
41 :
42 : SkRegion& operator=(const SkRegion&);
43 :
44 : /**
45 : * Return true if the two regions are equal. i.e. The enclose exactly
46 : * the same area.
47 : */
48 : friend bool operator==(const SkRegion& a, const SkRegion& b);
49 :
50 : /**
51 : * Return true if the two regions are not equal.
52 : */
53 : friend bool operator!=(const SkRegion& a, const SkRegion& b) {
54 : return !(a == b);
55 : }
56 :
57 : /**
58 : * Replace this region with the specified region, and return true if the
59 : * resulting region is non-empty.
60 : */
61 0 : bool set(const SkRegion& src) {
62 0 : SkASSERT(&src);
63 0 : *this = src;
64 0 : return !this->isEmpty();
65 : }
66 :
67 : /**
68 : * Swap the contents of this and the specified region. This operation
69 : * is gauarenteed to never fail.
70 : */
71 : void swap(SkRegion&);
72 :
73 : /** Return true if this region is empty */
74 0 : bool isEmpty() const { return fRunHead == SkRegion_gEmptyRunHeadPtr; }
75 :
76 : /** Return true if this region is a single, non-empty rectangle */
77 0 : bool isRect() const { return fRunHead == SkRegion_gRectRunHeadPtr; }
78 :
79 : /** Return true if this region consists of more than 1 rectangular area */
80 0 : bool isComplex() const { return !this->isEmpty() && !this->isRect(); }
81 :
82 : /**
83 : * Return the bounds of this region. If the region is empty, returns an
84 : * empty rectangle.
85 : */
86 0 : const SkIRect& getBounds() const { return fBounds; }
87 :
88 : /**
89 : * Returns true if the region is non-empty, and if so, appends the
90 : * boundary(s) of the region to the specified path.
91 : * If the region is empty, returns false, and path is left unmodified.
92 : */
93 : bool getBoundaryPath(SkPath* path) const;
94 :
95 : /**
96 : * Set the region to be empty, and return false, since the resulting
97 : * region is empty
98 : */
99 : bool setEmpty();
100 :
101 : /**
102 : * If rect is non-empty, set this region to that rectangle and return true,
103 : * otherwise set this region to empty and return false.
104 : */
105 : bool setRect(const SkIRect&);
106 :
107 : /**
108 : * If left < right and top < bottom, set this region to that rectangle and
109 : * return true, otherwise set this region to empty and return false.
110 : */
111 : bool setRect(int32_t left, int32_t top, int32_t right, int32_t bottom);
112 :
113 : /**
114 : * Set this region to the union of an array of rects. This is generally
115 : * faster than calling region.op(rect, kUnion_Op) in a loop. If count is
116 : * 0, then this region is set to the empty region.
117 : * @return true if the resulting region is non-empty
118 : */
119 : bool setRects(const SkIRect rects[], int count);
120 :
121 : /**
122 : * Set this region to the specified region, and return true if it is
123 : * non-empty.
124 : */
125 : bool setRegion(const SkRegion&);
126 :
127 : /**
128 : * Set this region to the area described by the path, clipped.
129 : * Return true if the resulting region is non-empty.
130 : * This produces a region that is identical to the pixels that would be
131 : * drawn by the path (with no antialiasing) with the specified clip.
132 : */
133 : bool setPath(const SkPath&, const SkRegion& clip);
134 :
135 : /**
136 : * Returns true if the specified rectangle has a non-empty intersection
137 : * with this region.
138 : */
139 : bool intersects(const SkIRect&) const;
140 :
141 : /**
142 : * Returns true if the specified region has a non-empty intersection
143 : * with this region.
144 : */
145 : bool intersects(const SkRegion&) const;
146 :
147 : /**
148 : * Return true if the specified x,y coordinate is inside the region.
149 : */
150 : bool contains(int32_t x, int32_t y) const;
151 :
152 : /**
153 : * Return true if the specified rectangle is completely inside the region.
154 : * This works for simple (rectangular) and complex regions, and always
155 : * returns the correct result. Note: if either this region or the rectangle
156 : * is empty, contains() returns false.
157 : */
158 : bool contains(const SkIRect&) const;
159 :
160 : /**
161 : * Return true if the specified region is completely inside the region.
162 : * This works for simple (rectangular) and complex regions, and always
163 : * returns the correct result. Note: if either region is empty, contains()
164 : * returns false.
165 : */
166 : bool contains(const SkRegion&) const;
167 :
168 : /**
169 : * Return true if this region is a single rectangle (not complex) and the
170 : * specified rectangle is contained by this region. Returning false is not
171 : * a guarantee that the rectangle is not contained by this region, but
172 : * return true is a guarantee that the rectangle is contained by this region.
173 : */
174 0 : bool quickContains(const SkIRect& r) const {
175 0 : return this->quickContains(r.fLeft, r.fTop, r.fRight, r.fBottom);
176 : }
177 :
178 : /**
179 : * Return true if this region is a single rectangle (not complex) and the
180 : * specified rectangle is contained by this region. Returning false is not
181 : * a guarantee that the rectangle is not contained by this region, but
182 : * return true is a guarantee that the rectangle is contained by this
183 : * region.
184 : */
185 0 : bool quickContains(int32_t left, int32_t top, int32_t right,
186 : int32_t bottom) const {
187 0 : SkASSERT(this->isEmpty() == fBounds.isEmpty()); // valid region
188 :
189 : return left < right && top < bottom &&
190 : fRunHead == SkRegion_gRectRunHeadPtr && // this->isRect()
191 : /* fBounds.contains(left, top, right, bottom); */
192 : fBounds.fLeft <= left && fBounds.fTop <= top &&
193 0 : fBounds.fRight >= right && fBounds.fBottom >= bottom;
194 : }
195 :
196 : /**
197 : * Return true if this region is empty, or if the specified rectangle does
198 : * not intersect the region. Returning false is not a guarantee that they
199 : * intersect, but returning true is a guarantee that they do not.
200 : */
201 0 : bool quickReject(const SkIRect& rect) const {
202 0 : return this->isEmpty() || rect.isEmpty() ||
203 0 : !SkIRect::Intersects(fBounds, rect);
204 : }
205 :
206 : /**
207 : * Return true if this region, or rgn, is empty, or if their bounds do not
208 : * intersect. Returning false is not a guarantee that they intersect, but
209 : * returning true is a guarantee that they do not.
210 : */
211 : bool quickReject(const SkRegion& rgn) const {
212 : return this->isEmpty() || rgn.isEmpty() ||
213 : !SkIRect::Intersects(fBounds, rgn.fBounds);
214 : }
215 :
216 : /** Translate the region by the specified (dx, dy) amount. */
217 : void translate(int dx, int dy) { this->translate(dx, dy, this); }
218 :
219 : /**
220 : * Translate the region by the specified (dx, dy) amount, writing the
221 : * resulting region into dst. Note: it is legal to pass this region as the
222 : * dst parameter, effectively translating the region in place. If dst is
223 : * null, nothing happens.
224 : */
225 : void translate(int dx, int dy, SkRegion* dst) const;
226 :
227 : /**
228 : * The logical operations that can be performed when combining two regions.
229 : */
230 : enum Op {
231 : kDifference_Op, //!< subtract the op region from the first region
232 : kIntersect_Op, //!< intersect the two regions
233 : kUnion_Op, //!< union (inclusive-or) the two regions
234 : kXOR_Op, //!< exclusive-or the two regions
235 : /** subtract the first region from the op region */
236 : kReverseDifference_Op,
237 : kReplace_Op //!< replace the dst region with the op region
238 : };
239 :
240 : /**
241 : * Set this region to the result of applying the Op to this region and the
242 : * specified rectangle: this = (this op rect).
243 : * Return true if the resulting region is non-empty.
244 : */
245 0 : bool op(const SkIRect& rect, Op op) { return this->op(*this, rect, op); }
246 :
247 : /**
248 : * Set this region to the result of applying the Op to this region and the
249 : * specified rectangle: this = (this op rect).
250 : * Return true if the resulting region is non-empty.
251 : */
252 : bool op(int left, int top, int right, int bottom, Op op) {
253 : SkIRect rect;
254 : rect.set(left, top, right, bottom);
255 : return this->op(*this, rect, op);
256 : }
257 :
258 : /**
259 : * Set this region to the result of applying the Op to this region and the
260 : * specified region: this = (this op rgn).
261 : * Return true if the resulting region is non-empty.
262 : */
263 0 : bool op(const SkRegion& rgn, Op op) { return this->op(*this, rgn, op); }
264 :
265 : /**
266 : * Set this region to the result of applying the Op to the specified
267 : * rectangle and region: this = (rect op rgn).
268 : * Return true if the resulting region is non-empty.
269 : */
270 : bool op(const SkIRect& rect, const SkRegion& rgn, Op);
271 :
272 : /**
273 : * Set this region to the result of applying the Op to the specified
274 : * region and rectangle: this = (rgn op rect).
275 : * Return true if the resulting region is non-empty.
276 : */
277 : bool op(const SkRegion& rgn, const SkIRect& rect, Op);
278 :
279 : /**
280 : * Set this region to the result of applying the Op to the specified
281 : * regions: this = (rgna op rgnb).
282 : * Return true if the resulting region is non-empty.
283 : */
284 : bool op(const SkRegion& rgna, const SkRegion& rgnb, Op op);
285 :
286 : #ifdef SK_BUILD_FOR_ANDROID
287 : /** Returns a new char* containing the list of rectangles in this region
288 : */
289 : char* toString();
290 : #endif
291 :
292 : /**
293 : * Returns the sequence of rectangles, sorted in Y and X, that make up
294 : * this region.
295 : */
296 : class SK_API Iterator {
297 : public:
298 : Iterator() : fRgn(NULL), fDone(true) {}
299 : Iterator(const SkRegion&);
300 : // if we have a region, reset to it and return true, else return false
301 : bool rewind();
302 : // reset the iterator, using the new region
303 : void reset(const SkRegion&);
304 0 : bool done() const { return fDone; }
305 : void next();
306 0 : const SkIRect& rect() const { return fRect; }
307 : // may return null
308 : const SkRegion* rgn() const { return fRgn; }
309 :
310 : private:
311 : const SkRegion* fRgn;
312 : const RunType* fRuns;
313 : SkIRect fRect;
314 : bool fDone;
315 : };
316 :
317 : /**
318 : * Returns the sequence of rectangles, sorted in Y and X, that make up
319 : * this region intersected with the specified clip rectangle.
320 : */
321 : class SK_API Cliperator {
322 : public:
323 : Cliperator(const SkRegion&, const SkIRect& clip);
324 0 : bool done() { return fDone; }
325 : void next();
326 0 : const SkIRect& rect() const { return fRect; }
327 :
328 : private:
329 : Iterator fIter;
330 : SkIRect fClip;
331 : SkIRect fRect;
332 : bool fDone;
333 : };
334 :
335 : /**
336 : * Returns the sequence of runs that make up this region for the specified
337 : * Y scanline, clipped to the specified left and right X values.
338 : */
339 : class Spanerator {
340 : public:
341 : Spanerator(const SkRegion&, int y, int left, int right);
342 : bool next(int* left, int* right);
343 :
344 : private:
345 : const SkRegion::RunType* fRuns;
346 : int fLeft, fRight;
347 : bool fDone;
348 : };
349 :
350 : /**
351 : * Write the region to the buffer, and return the number of bytes written.
352 : * If buffer is NULL, it still returns the number of bytes.
353 : */
354 : uint32_t flatten(void* buffer) const;
355 :
356 : /**
357 : * Initialized the region from the buffer, returning the number
358 : * of bytes actually read.
359 : */
360 : uint32_t unflatten(const void* buffer);
361 :
362 : /**
363 : * Returns a reference to a global empty region. Just a convenience for
364 : * callers that need a const empty region.
365 : */
366 : static const SkRegion& GetEmptyRegion();
367 :
368 : SkDEBUGCODE(void dump() const;)
369 : SkDEBUGCODE(void validate() const;)
370 : SkDEBUGCODE(static void UnitTest();)
371 :
372 : // expose this to allow for regression test on complex regions
373 : SkDEBUGCODE(bool debugSetRuns(const RunType runs[], int count);)
374 :
375 : private:
376 : enum {
377 : kOpCount = kReplace_Op + 1
378 : };
379 :
380 : enum {
381 : kRectRegionRuns = 6 // need to store a region of a rect [T B L R S S]
382 : };
383 :
384 : friend class android::Region; // needed for marshalling efficiently
385 : void allocateRuns(int count); // allocate space for count runs
386 :
387 : struct RunHead;
388 :
389 : SkIRect fBounds;
390 : RunHead* fRunHead;
391 :
392 : void freeRuns();
393 : const RunType* getRuns(RunType tmpStorage[], int* count) const;
394 : bool setRuns(RunType runs[], int count);
395 :
396 : int count_runtype_values(int* itop, int* ibot) const;
397 :
398 : static void BuildRectRuns(const SkIRect& bounds,
399 : RunType runs[kRectRegionRuns]);
400 : // returns true if runs are just a rect
401 : static bool ComputeRunBounds(const RunType runs[], int count,
402 : SkIRect* bounds);
403 :
404 : friend struct RunHead;
405 : friend class Iterator;
406 : friend class Spanerator;
407 : friend class SkRgnBuilder;
408 : friend class SkFlatRegion;
409 : };
410 :
411 : #endif
|